|
@@ -0,0 +1,426 @@
|
|
|
|
|
+#!/usr/bin/env python3
|
|
|
|
|
+
|
|
|
|
|
+import re
|
|
|
|
|
+import sys
|
|
|
|
|
+
|
|
|
|
|
+# NOTE the use of macros here helps keep a consistent stack depth which
|
|
|
|
|
+# tools may rely on.
|
|
|
|
|
+#
|
|
|
|
|
+# If compilation errors are noisy consider using -ftrack-macro-expansion=0.
|
|
|
|
|
+#
|
|
|
|
|
+
|
|
|
|
|
+LIMIT = 16
|
|
|
|
|
+
|
|
|
|
|
+CMP = {
|
|
|
|
|
+ '==': 'eq',
|
|
|
|
|
+ '!=': 'ne',
|
|
|
|
|
+ '<=': 'le',
|
|
|
|
|
+ '>=': 'ge',
|
|
|
|
|
+ '<': 'lt',
|
|
|
|
|
+ '>': 'gt',
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+LEXEMES = {
|
|
|
|
|
+ 'ws': [r'(?:\s|\n|#.*?\n|//.*?\n|/\*.*?\*/)+'],
|
|
|
|
|
+ 'assert': ['assert'],
|
|
|
|
|
+ 'arrow': ['=>'],
|
|
|
|
|
+ 'string': [r'"(?:\\.|[^"])*"', r"'(?:\\.|[^'])\'"],
|
|
|
|
|
+ 'paren': ['\(', '\)'],
|
|
|
|
|
+ 'cmp': CMP.keys(),
|
|
|
|
|
+ 'logic': ['\&\&', '\|\|'],
|
|
|
|
|
+ 'sep': [':', ';', '\{', '\}', ','],
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def openio(path, mode='r'):
|
|
|
|
|
+ if path == '-':
|
|
|
|
|
+ if 'r' in mode:
|
|
|
|
|
+ return os.fdopen(os.dup(sys.stdin.fileno()), 'r')
|
|
|
|
|
+ else:
|
|
|
|
|
+ return os.fdopen(os.dup(sys.stdout.fileno()), 'w')
|
|
|
|
|
+ else:
|
|
|
|
|
+ return open(path, mode)
|
|
|
|
|
+
|
|
|
|
|
+def write_header(f, limit=LIMIT):
|
|
|
|
|
+ f.writeln("// Generated by %s:" % sys.argv[0])
|
|
|
|
|
+ f.writeln("//")
|
|
|
|
|
+ f.writeln("// %s" % ' '.join(sys.argv))
|
|
|
|
|
+ f.writeln("//")
|
|
|
|
|
+ f.writeln()
|
|
|
|
|
+
|
|
|
|
|
+ f.writeln("#include <stdio.h>")
|
|
|
|
|
+ f.writeln("#include <stdbool.h>")
|
|
|
|
|
+ f.writeln("#include <stdint.h>")
|
|
|
|
|
+ f.writeln("#include <inttypes.h>")
|
|
|
|
|
+ f.writeln("#include <signal.h>")
|
|
|
|
|
+ f.writeln()
|
|
|
|
|
+
|
|
|
|
|
+ # write print macros
|
|
|
|
|
+ f.writeln("__attribute__((unused))")
|
|
|
|
|
+ f.writeln("static void __pretty_assert_print_bool(")
|
|
|
|
|
+ f.writeln(" const void *v, size_t size) {")
|
|
|
|
|
+ f.writeln(" (void)size;")
|
|
|
|
|
+ f.writeln(" printf(\"%s\", *(const bool*)v ? \"true\" : \"false\");")
|
|
|
|
|
+ f.writeln("}")
|
|
|
|
|
+ f.writeln()
|
|
|
|
|
+ f.writeln("__attribute__((unused))")
|
|
|
|
|
+ f.writeln("static void __pretty_assert_print_int(")
|
|
|
|
|
+ f.writeln(" const void *v, size_t size) {")
|
|
|
|
|
+ f.writeln(" (void)size;")
|
|
|
|
|
+ f.writeln(" printf(\"%\"PRIiMAX, *(const intmax_t*)v);")
|
|
|
|
|
+ f.writeln("}")
|
|
|
|
|
+ f.writeln()
|
|
|
|
|
+ f.writeln("__attribute__((unused))")
|
|
|
|
|
+ f.writeln("static void __pretty_assert_print_mem(")
|
|
|
|
|
+ f.writeln(" const void *v, size_t size) {")
|
|
|
|
|
+ f.writeln(" const uint8_t *v_ = v;")
|
|
|
|
|
+ f.writeln(" printf(\"\\\"\");")
|
|
|
|
|
+ f.writeln(" for (size_t i = 0; i < size && i < %d; i++) {" % limit)
|
|
|
|
|
+ f.writeln(" if (v_[i] >= ' ' && v_[i] <= '~') {")
|
|
|
|
|
+ f.writeln(" printf(\"%c\", v_[i]);")
|
|
|
|
|
+ f.writeln(" } else {")
|
|
|
|
|
+ f.writeln(" printf(\"\\\\x%02x\", v_[i]);")
|
|
|
|
|
+ f.writeln(" }")
|
|
|
|
|
+ f.writeln(" }")
|
|
|
|
|
+ f.writeln(" if (size > %d) {" % limit)
|
|
|
|
|
+ f.writeln(" printf(\"...\");")
|
|
|
|
|
+ f.writeln(" }")
|
|
|
|
|
+ f.writeln(" printf(\"\\\"\");")
|
|
|
|
|
+ f.writeln("}")
|
|
|
|
|
+ f.writeln()
|
|
|
|
|
+ f.writeln("__attribute__((unused))")
|
|
|
|
|
+ f.writeln("static void __pretty_assert_print_str(")
|
|
|
|
|
+ f.writeln(" const void *v, size_t size) {")
|
|
|
|
|
+ f.writeln(" __pretty_assert_print_mem(v, size);")
|
|
|
|
|
+ f.writeln("}")
|
|
|
|
|
+ f.writeln()
|
|
|
|
|
+ f.writeln("__attribute__((unused, noinline))")
|
|
|
|
|
+ f.writeln("static void __pretty_assert_fail(")
|
|
|
|
|
+ f.writeln(" const char *file, int line,")
|
|
|
|
|
+ f.writeln(" void (*type_print_cb)(const void*, size_t),")
|
|
|
|
|
+ f.writeln(" const char *cmp,")
|
|
|
|
|
+ f.writeln(" const void *lh, size_t lsize,")
|
|
|
|
|
+ f.writeln(" const void *rh, size_t rsize) {")
|
|
|
|
|
+ f.writeln(" printf(\"%s:%d:assert: assert failed with \", file, line);")
|
|
|
|
|
+ f.writeln(" type_print_cb(lh, lsize);")
|
|
|
|
|
+ f.writeln(" printf(\", expected %s \", cmp);")
|
|
|
|
|
+ f.writeln(" type_print_cb(rh, rsize);")
|
|
|
|
|
+ f.writeln(" printf(\"\\n\");")
|
|
|
|
|
+ f.writeln(" fflush(NULL);")
|
|
|
|
|
+ f.writeln(" raise(SIGABRT);")
|
|
|
|
|
+ f.writeln("}")
|
|
|
|
|
+ f.writeln()
|
|
|
|
|
+
|
|
|
|
|
+ # write assert macros
|
|
|
|
|
+ for op, cmp in sorted(CMP.items()):
|
|
|
|
|
+ f.writeln("#define __PRETTY_ASSERT_BOOL_%s(lh, rh) do { \\"
|
|
|
|
|
+ % cmp.upper())
|
|
|
|
|
+ f.writeln(" bool _lh = !!(lh); \\")
|
|
|
|
|
+ f.writeln(" bool _rh = !!(rh); \\")
|
|
|
|
|
+ f.writeln(" if (!(_lh %s _rh)) { \\" % op)
|
|
|
|
|
+ f.writeln(" __pretty_assert_fail( \\")
|
|
|
|
|
+ f.writeln(" __FILE__, __LINE__, \\")
|
|
|
|
|
+ f.writeln(" __pretty_assert_print_bool, \"%s\", \\"
|
|
|
|
|
+ % cmp)
|
|
|
|
|
+ f.writeln(" &_lh, 0, \\")
|
|
|
|
|
+ f.writeln(" &_rh, 0); \\")
|
|
|
|
|
+ f.writeln(" } \\")
|
|
|
|
|
+ f.writeln("} while (0)")
|
|
|
|
|
+ for op, cmp in sorted(CMP.items()):
|
|
|
|
|
+ f.writeln("#define __PRETTY_ASSERT_INT_%s(lh, rh) do { \\"
|
|
|
|
|
+ % cmp.upper())
|
|
|
|
|
+ f.writeln(" __typeof__(lh) _lh = lh; \\")
|
|
|
|
|
+ f.writeln(" __typeof__(lh) _rh = rh; \\")
|
|
|
|
|
+ f.writeln(" if (!(_lh %s _rh)) { \\" % op)
|
|
|
|
|
+ f.writeln(" __pretty_assert_fail( \\")
|
|
|
|
|
+ f.writeln(" __FILE__, __LINE__, \\")
|
|
|
|
|
+ f.writeln(" __pretty_assert_print_int, \"%s\", \\"
|
|
|
|
|
+ % cmp)
|
|
|
|
|
+ f.writeln(" &(intmax_t){_lh}, 0, \\")
|
|
|
|
|
+ f.writeln(" &(intmax_t){_rh}, 0); \\")
|
|
|
|
|
+ f.writeln(" } \\")
|
|
|
|
|
+ f.writeln("} while (0)")
|
|
|
|
|
+ for op, cmp in sorted(CMP.items()):
|
|
|
|
|
+ f.writeln("#define __PRETTY_ASSERT_MEM_%s(lh, rh, size) do { \\"
|
|
|
|
|
+ % cmp.upper())
|
|
|
|
|
+ f.writeln(" const void *_lh = lh; \\")
|
|
|
|
|
+ f.writeln(" const void *_rh = rh; \\")
|
|
|
|
|
+ f.writeln(" if (!(memcmp(_lh, _rh, size) %s 0)) { \\" % op)
|
|
|
|
|
+ f.writeln(" __pretty_assert_fail( \\")
|
|
|
|
|
+ f.writeln(" __FILE__, __LINE__, \\")
|
|
|
|
|
+ f.writeln(" __pretty_assert_print_mem, \"%s\", \\"
|
|
|
|
|
+ % cmp)
|
|
|
|
|
+ f.writeln(" _lh, size, \\")
|
|
|
|
|
+ f.writeln(" _rh, size); \\")
|
|
|
|
|
+ f.writeln(" } \\")
|
|
|
|
|
+ f.writeln("} while (0)")
|
|
|
|
|
+ for op, cmp in sorted(CMP.items()):
|
|
|
|
|
+ f.writeln("#define __PRETTY_ASSERT_STR_%s(lh, rh) do { \\"
|
|
|
|
|
+ % cmp.upper())
|
|
|
|
|
+ f.writeln(" const char *_lh = lh; \\")
|
|
|
|
|
+ f.writeln(" const char *_rh = rh; \\")
|
|
|
|
|
+ f.writeln(" if (!(strcmp(_lh, _rh) %s 0)) { \\" % op)
|
|
|
|
|
+ f.writeln(" __pretty_assert_fail( \\")
|
|
|
|
|
+ f.writeln(" __FILE__, __LINE__, \\")
|
|
|
|
|
+ f.writeln(" __pretty_assert_print_str, \"%s\", \\"
|
|
|
|
|
+ % cmp)
|
|
|
|
|
+ f.writeln(" _lh, strlen(_lh), \\")
|
|
|
|
|
+ f.writeln(" _rh, strlen(_rh)); \\")
|
|
|
|
|
+ f.writeln(" } \\")
|
|
|
|
|
+ f.writeln("} while (0)")
|
|
|
|
|
+ f.writeln()
|
|
|
|
|
+ f.writeln()
|
|
|
|
|
+
|
|
|
|
|
+def mkassert(type, cmp, lh, rh, size=None):
|
|
|
|
|
+ if size is not None:
|
|
|
|
|
+ return ("__PRETTY_ASSERT_%s_%s(%s, %s, %s)"
|
|
|
|
|
+ % (type.upper(), cmp.upper(), lh, rh, size))
|
|
|
|
|
+ else:
|
|
|
|
|
+ return ("__PRETTY_ASSERT_%s_%s(%s, %s)"
|
|
|
|
|
+ % (type.upper(), cmp.upper(), lh, rh))
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+# simple recursive descent parser
|
|
|
|
|
+class ParseFailure(Exception):
|
|
|
|
|
+ def __init__(self, expected, found):
|
|
|
|
|
+ self.expected = expected
|
|
|
|
|
+ self.found = found
|
|
|
|
|
+
|
|
|
|
|
+ def __str__(self):
|
|
|
|
|
+ return "expected %r, found %s..." % (
|
|
|
|
|
+ self.expected, repr(self.found)[:70])
|
|
|
|
|
+
|
|
|
|
|
+class Parser:
|
|
|
|
|
+ def __init__(self, in_f, lexemes=LEXEMES):
|
|
|
|
|
+ p = '|'.join('(?P<%s>%s)' % (n, '|'.join(l))
|
|
|
|
|
+ for n, l in lexemes.items())
|
|
|
|
|
+ p = re.compile(p, re.DOTALL)
|
|
|
|
|
+ data = in_f.read()
|
|
|
|
|
+ tokens = []
|
|
|
|
|
+ line = 1
|
|
|
|
|
+ col = 0
|
|
|
|
|
+ while True:
|
|
|
|
|
+ m = p.search(data)
|
|
|
|
|
+ if m:
|
|
|
|
|
+ if m.start() > 0:
|
|
|
|
|
+ tokens.append((None, data[:m.start()], line, col))
|
|
|
|
|
+ tokens.append((m.lastgroup, m.group(), line, col))
|
|
|
|
|
+ data = data[m.end():]
|
|
|
|
|
+ else:
|
|
|
|
|
+ tokens.append((None, data, line, col))
|
|
|
|
|
+ break
|
|
|
|
|
+ self.tokens = tokens
|
|
|
|
|
+ self.off = 0
|
|
|
|
|
+
|
|
|
|
|
+ def lookahead(self, *pattern):
|
|
|
|
|
+ if self.off < len(self.tokens):
|
|
|
|
|
+ token = self.tokens[self.off]
|
|
|
|
|
+ if token[0] in pattern or token[1] in pattern:
|
|
|
|
|
+ self.m = token[1]
|
|
|
|
|
+ return self.m
|
|
|
|
|
+ self.m = None
|
|
|
|
|
+ return self.m
|
|
|
|
|
+
|
|
|
|
|
+ def accept(self, *patterns):
|
|
|
|
|
+ m = self.lookahead(*patterns)
|
|
|
|
|
+ if m is not None:
|
|
|
|
|
+ self.off += 1
|
|
|
|
|
+ return m
|
|
|
|
|
+
|
|
|
|
|
+ def expect(self, *patterns):
|
|
|
|
|
+ m = self.accept(*patterns)
|
|
|
|
|
+ if not m:
|
|
|
|
|
+ raise ParseFailure(patterns, self.tokens[self.off:])
|
|
|
|
|
+ return m
|
|
|
|
|
+
|
|
|
|
|
+ def push(self):
|
|
|
|
|
+ return self.off
|
|
|
|
|
+
|
|
|
|
|
+ def pop(self, state):
|
|
|
|
|
+ self.off = state
|
|
|
|
|
+
|
|
|
|
|
+def p_assert(p):
|
|
|
|
|
+ state = p.push()
|
|
|
|
|
+
|
|
|
|
|
+ # assert(memcmp(a,b,size) cmp 0)?
|
|
|
|
|
+ try:
|
|
|
|
|
+ p.expect('assert') ; p.accept('ws')
|
|
|
|
|
+ p.expect('(') ; p.accept('ws')
|
|
|
|
|
+ p.expect('memcmp') ; p.accept('ws')
|
|
|
|
|
+ p.expect('(') ; p.accept('ws')
|
|
|
|
|
+ lh = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(',') ; p.accept('ws')
|
|
|
|
|
+ rh = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(',') ; p.accept('ws')
|
|
|
|
|
+ size = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(')') ; p.accept('ws')
|
|
|
|
|
+ cmp = p.expect('cmp') ; p.accept('ws')
|
|
|
|
|
+ p.expect('0') ; p.accept('ws')
|
|
|
|
|
+ p.expect(')')
|
|
|
|
|
+ return mkassert('mem', CMP[cmp], lh, rh, size)
|
|
|
|
|
+ except ParseFailure:
|
|
|
|
|
+ p.pop(state)
|
|
|
|
|
+
|
|
|
|
|
+ # assert(strcmp(a,b) cmp 0)?
|
|
|
|
|
+ try:
|
|
|
|
|
+ p.expect('assert') ; p.accept('ws')
|
|
|
|
|
+ p.expect('(') ; p.accept('ws')
|
|
|
|
|
+ p.expect('strcmp') ; p.accept('ws')
|
|
|
|
|
+ p.expect('(') ; p.accept('ws')
|
|
|
|
|
+ lh = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(',') ; p.accept('ws')
|
|
|
|
|
+ rh = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(')') ; p.accept('ws')
|
|
|
|
|
+ cmp = p.expect('cmp') ; p.accept('ws')
|
|
|
|
|
+ p.expect('0') ; p.accept('ws')
|
|
|
|
|
+ p.expect(')')
|
|
|
|
|
+ return mkassert('str', CMP[cmp], lh, rh)
|
|
|
|
|
+ except ParseFailure:
|
|
|
|
|
+ p.pop(state)
|
|
|
|
|
+
|
|
|
|
|
+ # assert(a cmp b)?
|
|
|
|
|
+ try:
|
|
|
|
|
+ p.expect('assert') ; p.accept('ws')
|
|
|
|
|
+ p.expect('(') ; p.accept('ws')
|
|
|
|
|
+ lh = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ cmp = p.expect('cmp') ; p.accept('ws')
|
|
|
|
|
+ rh = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(')')
|
|
|
|
|
+ return mkassert('int', CMP[cmp], lh, rh)
|
|
|
|
|
+ except ParseFailure:
|
|
|
|
|
+ p.pop(state)
|
|
|
|
|
+
|
|
|
|
|
+ # assert(a)?
|
|
|
|
|
+ p.expect('assert') ; p.accept('ws')
|
|
|
|
|
+ p.expect('(') ; p.accept('ws')
|
|
|
|
|
+ lh = p_exprs(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(')')
|
|
|
|
|
+ return mkassert('bool', 'eq', lh, 'true')
|
|
|
|
|
+
|
|
|
|
|
+def p_expr(p):
|
|
|
|
|
+ res = []
|
|
|
|
|
+ while True:
|
|
|
|
|
+ if p.accept('('):
|
|
|
|
|
+ res.append(p.m)
|
|
|
|
|
+ while True:
|
|
|
|
|
+ res.append(p_exprs(p))
|
|
|
|
|
+ if p.accept('sep'):
|
|
|
|
|
+ res.append(p.m)
|
|
|
|
|
+ else:
|
|
|
|
|
+ break
|
|
|
|
|
+ res.append(p.expect(')'))
|
|
|
|
|
+ elif p.lookahead('assert'):
|
|
|
|
|
+ state = p.push()
|
|
|
|
|
+ try:
|
|
|
|
|
+ res.append(p_assert(p))
|
|
|
|
|
+ except ParseFailure:
|
|
|
|
|
+ p.pop(state)
|
|
|
|
|
+ res.append(p.expect('assert'))
|
|
|
|
|
+ elif p.accept('string', None, 'ws'):
|
|
|
|
|
+ res.append(p.m)
|
|
|
|
|
+ else:
|
|
|
|
|
+ return ''.join(res)
|
|
|
|
|
+
|
|
|
|
|
+def p_exprs(p):
|
|
|
|
|
+ res = []
|
|
|
|
|
+ while True:
|
|
|
|
|
+ res.append(p_expr(p))
|
|
|
|
|
+ if p.accept('cmp', 'logic', ','):
|
|
|
|
|
+ res.append(p.m)
|
|
|
|
|
+ else:
|
|
|
|
|
+ return ''.join(res)
|
|
|
|
|
+
|
|
|
|
|
+def p_stmt(p):
|
|
|
|
|
+ ws = p.accept('ws') or ''
|
|
|
|
|
+
|
|
|
|
|
+ # memcmp(lh,rh,size) => 0?
|
|
|
|
|
+ if p.lookahead('memcmp'):
|
|
|
|
|
+ state = p.push()
|
|
|
|
|
+ try:
|
|
|
|
|
+ p.expect('memcmp') ; p.accept('ws')
|
|
|
|
|
+ p.expect('(') ; p.accept('ws')
|
|
|
|
|
+ lh = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(',') ; p.accept('ws')
|
|
|
|
|
+ rh = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(',') ; p.accept('ws')
|
|
|
|
|
+ size = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(')') ; p.accept('ws')
|
|
|
|
|
+ p.expect('=>') ; p.accept('ws')
|
|
|
|
|
+ p.expect('0') ; p.accept('ws')
|
|
|
|
|
+ return ws + mkassert('mem', 'eq', lh, rh, size)
|
|
|
|
|
+ except ParseFailure:
|
|
|
|
|
+ p.pop(state)
|
|
|
|
|
+
|
|
|
|
|
+ # strcmp(lh,rh) => 0?
|
|
|
|
|
+ if p.lookahead('strcmp'):
|
|
|
|
|
+ state = p.push()
|
|
|
|
|
+ try:
|
|
|
|
|
+ p.expect('strcmp') ; p.accept('ws') ; p.expect('(') ; p.accept('ws')
|
|
|
|
|
+ lh = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(',') ; p.accept('ws')
|
|
|
|
|
+ rh = p_expr(p) ; p.accept('ws')
|
|
|
|
|
+ p.expect(')') ; p.accept('ws')
|
|
|
|
|
+ p.expect('=>') ; p.accept('ws')
|
|
|
|
|
+ p.expect('0') ; p.accept('ws')
|
|
|
|
|
+ return ws + mkassert('str', 'eq', lh, rh)
|
|
|
|
|
+ except ParseFailure:
|
|
|
|
|
+ p.pop(state)
|
|
|
|
|
+
|
|
|
|
|
+ # lh => rh?
|
|
|
|
|
+ lh = p_exprs(p)
|
|
|
|
|
+ if p.accept('=>'):
|
|
|
|
|
+ rh = p_exprs(p)
|
|
|
|
|
+ return ws + mkassert('int', 'eq', lh, rh)
|
|
|
|
|
+ else:
|
|
|
|
|
+ return ws + lh
|
|
|
|
|
+
|
|
|
|
|
+def main(input=None, output=None, pattern=[], limit=LIMIT):
|
|
|
|
|
+ with openio(input or '-', 'r') as in_f:
|
|
|
|
|
+ # create parser
|
|
|
|
|
+ lexemes = LEXEMES.copy()
|
|
|
|
|
+ lexemes['assert'] += pattern
|
|
|
|
|
+ p = Parser(in_f, lexemes)
|
|
|
|
|
+
|
|
|
|
|
+ with openio(output or '-', 'w') as f:
|
|
|
|
|
+ def writeln(s=''):
|
|
|
|
|
+ f.write(s)
|
|
|
|
|
+ f.write('\n')
|
|
|
|
|
+ f.writeln = writeln
|
|
|
|
|
+
|
|
|
|
|
+ # write extra verbose asserts
|
|
|
|
|
+ write_header(f, limit=limit)
|
|
|
|
|
+ if input is not None:
|
|
|
|
|
+ f.writeln("#line %d \"%s\"" % (1, input))
|
|
|
|
|
+
|
|
|
|
|
+ # parse and write out stmt at a time
|
|
|
|
|
+ try:
|
|
|
|
|
+ while True:
|
|
|
|
|
+ f.write(p_stmt(p))
|
|
|
|
|
+ if p.accept('sep'):
|
|
|
|
|
+ f.write(p.m)
|
|
|
|
|
+ else:
|
|
|
|
|
+ break
|
|
|
|
|
+ except ParseFailure as f:
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
|
|
+ for i in range(p.off, len(p.tokens)):
|
|
|
|
|
+ f.write(p.tokens[i][1])
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+if __name__ == "__main__":
|
|
|
|
|
+ import argparse
|
|
|
|
|
+ import sys
|
|
|
|
|
+ parser = argparse.ArgumentParser(
|
|
|
|
|
+ description="Preprocessor that makes asserts easy to debug.")
|
|
|
|
|
+ parser.add_argument('input',
|
|
|
|
|
+ help="Input C file.")
|
|
|
|
|
+ parser.add_argument('-o', '--output', required=True,
|
|
|
|
|
+ help="Output C file.")
|
|
|
|
|
+ parser.add_argument('-p', '--pattern', action='append',
|
|
|
|
|
+ help="Regex patterns to search for starting an assert statement. This"
|
|
|
|
|
+ " implicitly includes \"assert\" and \"=>\".")
|
|
|
|
|
+ parser.add_argument('-l', '--limit', default=LIMIT, type=int,
|
|
|
|
|
+ help="Maximum number of characters to display in strcmp and memcmp.")
|
|
|
|
|
+ sys.exit(main(**{k: v
|
|
|
|
|
+ for k, v in vars(parser.parse_args()).items()
|
|
|
|
|
+ if v is not None}))
|