|
|
@@ -1,208 +1,372 @@
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
-import parsy as p
|
|
|
import re
|
|
|
-import io
|
|
|
import sys
|
|
|
|
|
|
-ASSERT_PATTERN = p.string('LFS_ASSERT') | p.string('assert')
|
|
|
-ASSERT_CHARS = 'La'
|
|
|
-ASSERT_TARGET = '__LFS_ASSERT_{TYPE}_{COMP}'
|
|
|
-ASSERT_TESTS = {
|
|
|
- 'int': """
|
|
|
- __typeof__({lh}) _lh = {lh};
|
|
|
- __typeof__({lh}) _rh = (__typeof__({lh})){rh};
|
|
|
- if (!(_lh {op} _rh)) {{
|
|
|
- printf("%s:%d:assert: "
|
|
|
- "assert failed with %"PRIiMAX", expected {comp} %"PRIiMAX"\\n",
|
|
|
- {file}, {line}, (intmax_t)_lh, (intmax_t)_rh);
|
|
|
- fflush(NULL);
|
|
|
- raise(SIGABRT);
|
|
|
+PATTERN = ['LFS_ASSERT', 'assert']
|
|
|
+PREFIX = 'LFS'
|
|
|
+MAXWIDTH = 16
|
|
|
+
|
|
|
+ASSERT = "__{PREFIX}_ASSERT_{TYPE}_{COMP}"
|
|
|
+FAIL = """
|
|
|
+__attribute__((unused))
|
|
|
+static void __{prefix}_assert_fail_{type}(
|
|
|
+ const char *file, int line, const char *comp,
|
|
|
+ {ctype} lh, size_t lsize,
|
|
|
+ {ctype} rh, size_t rsize) {{
|
|
|
+ printf("%s:%d:assert: assert failed with ", file, line);
|
|
|
+ __{prefix}_assert_print_{type}(lh, lsize);
|
|
|
+ printf(", expected %s ", comp);
|
|
|
+ __{prefix}_assert_print_{type}(rh, rsize);
|
|
|
+ printf("\\n");
|
|
|
+ fflush(NULL);
|
|
|
+ raise(SIGABRT);
|
|
|
+}}
|
|
|
+"""
|
|
|
+
|
|
|
+COMP = {
|
|
|
+ '==': 'eq',
|
|
|
+ '!=': 'ne',
|
|
|
+ '<=': 'le',
|
|
|
+ '>=': 'ge',
|
|
|
+ '<': 'lt',
|
|
|
+ '>': 'gt',
|
|
|
+}
|
|
|
+
|
|
|
+TYPE = {
|
|
|
+ 'int': {
|
|
|
+ 'ctype': 'intmax_t',
|
|
|
+ 'fail': FAIL,
|
|
|
+ 'print': """
|
|
|
+ __attribute__((unused))
|
|
|
+ static void __{prefix}_assert_print_{type}({ctype} v, size_t size) {{
|
|
|
+ (void)size;
|
|
|
+ printf("%"PRIiMAX, v);
|
|
|
+ }}
|
|
|
+ """,
|
|
|
+ 'assert': """
|
|
|
+ #define __{PREFIX}_ASSERT_{TYPE}_{COMP}(file, line, lh, rh)
|
|
|
+ do {{
|
|
|
+ __typeof__(lh) _lh = lh;
|
|
|
+ __typeof__(lh) _rh = (__typeof__(lh))rh;
|
|
|
+ if (!(_lh {op} _rh)) {{
|
|
|
+ __{prefix}_assert_fail_{type}(file, line, "{comp}",
|
|
|
+ (intmax_t)_lh, 0, (intmax_t)_rh, 0);
|
|
|
+ }}
|
|
|
+ }} while (0)
|
|
|
+ """
|
|
|
+ },
|
|
|
+ 'bool': {
|
|
|
+ 'ctype': 'bool',
|
|
|
+ 'fail': FAIL,
|
|
|
+ 'print': """
|
|
|
+ __attribute__((unused))
|
|
|
+ static void __{prefix}_assert_print_{type}({ctype} v, size_t size) {{
|
|
|
+ (void)size;
|
|
|
+ printf("%s", v ? "true" : "false");
|
|
|
}}
|
|
|
- """,
|
|
|
- 'str': """
|
|
|
- const char *_lh = {lh};
|
|
|
- const char *_rh = {rh};
|
|
|
- if (!(strcmp(_lh, _rh) {op} 0)) {{
|
|
|
- printf("%s:%d:assert: "
|
|
|
- "assert failed with \\\"%s\\\", expected {comp} \\\"%s\\\"\\n",
|
|
|
- {file}, {line}, _lh, _rh);
|
|
|
- fflush(NULL);
|
|
|
- raise(SIGABRT);
|
|
|
+ """,
|
|
|
+ 'assert': """
|
|
|
+ #define __{PREFIX}_ASSERT_{TYPE}_{COMP}(file, line, lh, rh)
|
|
|
+ do {{
|
|
|
+ bool _lh = !!(lh);
|
|
|
+ bool _rh = !!(rh);
|
|
|
+ if (!(_lh {op} _rh)) {{
|
|
|
+ __{prefix}_assert_fail_{type}(file, line, "{comp}",
|
|
|
+ _lh, 0, _rh, 0);
|
|
|
+ }}
|
|
|
+ }} while (0)
|
|
|
+ """
|
|
|
+ },
|
|
|
+ 'mem': {
|
|
|
+ 'ctype': 'const void *',
|
|
|
+ 'fail': FAIL,
|
|
|
+ 'print': """
|
|
|
+ __attribute__((unused))
|
|
|
+ static void __{prefix}_assert_print_{type}({ctype} v, size_t size) {{
|
|
|
+ const uint8_t *s = v;
|
|
|
+ printf("\\\"");
|
|
|
+ for (size_t i = 0; i < size && i < {maxwidth}; i++) {{
|
|
|
+ if (s[i] >= ' ' && s[i] <= '~') {{
|
|
|
+ printf("%c", s[i]);
|
|
|
+ }} else {{
|
|
|
+ printf("\\\\x%02x", s[i]);
|
|
|
+ }}
|
|
|
+ }}
|
|
|
+ if (size > {maxwidth}) {{
|
|
|
+ printf("...");
|
|
|
+ }}
|
|
|
+ printf("\\\"");
|
|
|
}}
|
|
|
- """,
|
|
|
- 'bool': """
|
|
|
- bool _lh = !!({lh});
|
|
|
- bool _rh = !!({rh});
|
|
|
- if (!(_lh {op} _rh)) {{
|
|
|
- printf("%s:%d:assert: "
|
|
|
- "assert failed with %s, expected {comp} %s\\n",
|
|
|
- {file}, {line}, _lh ? "true" : "false", _rh ? "true" : "false");
|
|
|
- fflush(NULL);
|
|
|
- raise(SIGABRT);
|
|
|
+ """,
|
|
|
+ 'assert': """
|
|
|
+ #define __{PREFIX}_ASSERT_{TYPE}_{COMP}(file, line, lh, rh, size)
|
|
|
+ do {{
|
|
|
+ const void *_lh = lh;
|
|
|
+ const void *_rh = rh;
|
|
|
+ if (!(memcmp(_lh, _rh, size) {op} 0)) {{
|
|
|
+ __{prefix}_assert_fail_{type}(file, line, "{comp}",
|
|
|
+ _lh, size, _rh, size);
|
|
|
+ }}
|
|
|
+ }} while (0)
|
|
|
+ """
|
|
|
+ },
|
|
|
+ 'str': {
|
|
|
+ 'ctype': 'const char *',
|
|
|
+ 'fail': FAIL,
|
|
|
+ 'print': """
|
|
|
+ __attribute__((unused))
|
|
|
+ static void __{prefix}_assert_print_{type}({ctype} v, size_t size) {{
|
|
|
+ __{prefix}_assert_print_mem(v, size);
|
|
|
}}
|
|
|
- """,
|
|
|
+ """,
|
|
|
+ 'assert': """
|
|
|
+ #define __{PREFIX}_ASSERT_{TYPE}_{COMP}(file, line, lh, rh)
|
|
|
+ do {{
|
|
|
+ const char *_lh = lh;
|
|
|
+ const char *_rh = rh;
|
|
|
+ if (!(strcmp(_lh, _rh) {op} 0)) {{
|
|
|
+ __{prefix}_assert_fail_{type}(file, line, "{comp}",
|
|
|
+ _lh, strlen(_lh), _rh, strlen(_rh));
|
|
|
+ }}
|
|
|
+ }} while (0)
|
|
|
+ """
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-def mkassert(lh, rh='true', type='bool', comp='eq'):
|
|
|
- return ((ASSERT_TARGET + "({lh}, {rh}, __FILE__, __LINE__, __func__)")
|
|
|
- .format(
|
|
|
- type=type, TYPE=type.upper(),
|
|
|
- comp=comp, COMP=comp.upper(),
|
|
|
- lh=lh.strip(' '),
|
|
|
- rh=rh.strip(' ')))
|
|
|
-
|
|
|
-def mkdecl(type, comp, op):
|
|
|
- return ((
|
|
|
- "#define "+ASSERT_TARGET+"(lh, rh, file, line, func)"
|
|
|
- " do {{"+re.sub('\s+', ' ', ASSERT_TESTS[type])+"}} while (0)\n")
|
|
|
- .format(
|
|
|
- type=type, TYPE=type.upper(),
|
|
|
- comp=comp, COMP=comp.upper(),
|
|
|
- lh='lh', rh='rh', op=op,
|
|
|
- file='file', line='line', func='func'))
|
|
|
-
|
|
|
-# add custom until combinator
|
|
|
-def until(self, end):
|
|
|
- return end.should_fail('should fail').then(self).many()
|
|
|
-p.Parser.until = until
|
|
|
-
|
|
|
-pcomp = (
|
|
|
- p.string('==').tag('eq') |
|
|
|
- p.string('!=').tag('ne') |
|
|
|
- p.string('<=').tag('le') |
|
|
|
- p.string('>=').tag('ge') |
|
|
|
- p.string('<').tag('lt') |
|
|
|
- p.string('>').tag('gt'));
|
|
|
-
|
|
|
-plogic = p.string('&&') | p.string('||')
|
|
|
-
|
|
|
-@p.generate
|
|
|
-def pstrassert():
|
|
|
- yield ASSERT_PATTERN + p.regex('\s*') + p.string('(') + p.regex('\s*')
|
|
|
- yield p.string('strcmp') + p.regex('\s*') + p.string('(') + p.regex('\s*')
|
|
|
- lh = yield pexpr.until(p.string(',') | p.string(')') | plogic)
|
|
|
- yield p.string(',') + p.regex('\s*')
|
|
|
- rh = yield pexpr.until(p.string(')') | plogic)
|
|
|
- yield p.string(')') + p.regex('\s*')
|
|
|
- op = yield pcomp
|
|
|
- yield p.regex('\s*') + p.string('0') + p.regex('\s*') + p.string(')')
|
|
|
- return mkassert(''.join(lh), ''.join(rh), 'str', op[0])
|
|
|
-
|
|
|
-@p.generate
|
|
|
-def pintassert():
|
|
|
- yield ASSERT_PATTERN + p.regex('\s*') + p.string('(') + p.regex('\s*')
|
|
|
- lh = yield pexpr.until(pcomp | p.string(')') | plogic)
|
|
|
- op = yield pcomp
|
|
|
- rh = yield pexpr.until(p.string(')') | plogic)
|
|
|
- yield p.string(')')
|
|
|
- return mkassert(''.join(lh), ''.join(rh), 'int', op[0])
|
|
|
-
|
|
|
-@p.generate
|
|
|
-def pboolassert():
|
|
|
- yield ASSERT_PATTERN + p.regex('\s*') + p.string('(') + p.regex('\s*')
|
|
|
- expr = yield pexpr.until(p.string(')'))
|
|
|
- yield p.string(')')
|
|
|
- return mkassert(''.join(expr), 'true', 'bool', 'eq')
|
|
|
-
|
|
|
-passert = p.peek(ASSERT_PATTERN) >> (pstrassert | pintassert | pboolassert)
|
|
|
-
|
|
|
-@p.generate
|
|
|
-def pcomment1():
|
|
|
- yield p.string('//')
|
|
|
- s = yield p.regex('[^\\n]*')
|
|
|
- yield p.string('\n')
|
|
|
- return '//' + s + '\n'
|
|
|
-
|
|
|
-@p.generate
|
|
|
-def pcomment2():
|
|
|
- yield p.string('/*')
|
|
|
- s = yield p.regex('((?!\*/).)*')
|
|
|
- yield p.string('*/')
|
|
|
- return '/*' + ''.join(s) + '*/'
|
|
|
-
|
|
|
-@p.generate
|
|
|
-def pcomment3():
|
|
|
- yield p.string('#')
|
|
|
- s = yield p.regex('[^\\n]*')
|
|
|
- yield p.string('\n')
|
|
|
- return '#' + s + '\n'
|
|
|
-
|
|
|
-pws = p.regex('\s+') | pcomment1 | pcomment2 | pcomment3
|
|
|
-
|
|
|
-@p.generate
|
|
|
-def pstring():
|
|
|
- q = yield p.regex('["\']')
|
|
|
- s = yield (p.string('\\%s' % q) | p.regex('[^%s]' % q)).many()
|
|
|
- yield p.string(q)
|
|
|
- return q + ''.join(s) + q
|
|
|
-
|
|
|
-@p.generate
|
|
|
-def pnested():
|
|
|
- l = yield p.string('(')
|
|
|
- n = yield pexpr.until(p.string(')'))
|
|
|
- r = yield p.string(')')
|
|
|
- return l + ''.join(n) + r
|
|
|
-
|
|
|
-pexpr = (
|
|
|
- # shortcut for a bit better performance
|
|
|
- p.regex('[^%s/#\'"():;{}=><,&|-]+' % ASSERT_CHARS) |
|
|
|
- pws |
|
|
|
- passert |
|
|
|
- pstring |
|
|
|
- pnested |
|
|
|
- p.string('->') |
|
|
|
- p.regex('.', re.DOTALL))
|
|
|
-
|
|
|
-@p.generate
|
|
|
-def pstmt():
|
|
|
- ws = yield pws.many()
|
|
|
- lh = yield pexpr.until(p.string('=>') | p.regex('[:;{}]'))
|
|
|
- op = yield p.string('=>').optional()
|
|
|
- if op == '=>':
|
|
|
- rh = yield pstmt
|
|
|
- return ''.join(ws) + mkassert(''.join(lh), rh, 'int', 'eq')
|
|
|
+def mkdecls(outf, maxwidth=16):
|
|
|
+ outf.write("#include <stdio.h>\n")
|
|
|
+ outf.write("#include <stdbool.h>\n")
|
|
|
+ outf.write("#include <stdint.h>\n")
|
|
|
+ outf.write("#include <inttypes.h>\n")
|
|
|
+ outf.write("#include <signal.h>\n")
|
|
|
+
|
|
|
+ for type, desc in sorted(TYPE.items()):
|
|
|
+ format = {
|
|
|
+ 'type': type.lower(), 'TYPE': type.upper(),
|
|
|
+ 'ctype': desc['ctype'],
|
|
|
+ 'prefix': PREFIX.lower(), 'PREFIX': PREFIX.upper(),
|
|
|
+ 'maxwidth': maxwidth,
|
|
|
+ }
|
|
|
+ outf.write(re.sub('\s+', ' ',
|
|
|
+ desc['print'].strip().format(**format))+'\n')
|
|
|
+ outf.write(re.sub('\s+', ' ',
|
|
|
+ desc['fail'].strip().format(**format))+'\n')
|
|
|
+
|
|
|
+ for op, comp in sorted(COMP.items()):
|
|
|
+ format.update({
|
|
|
+ 'comp': comp.lower(), 'COMP': comp.upper(),
|
|
|
+ 'op': op,
|
|
|
+ })
|
|
|
+ outf.write(re.sub('\s+', ' ',
|
|
|
+ desc['assert'].strip().format(**format))+'\n')
|
|
|
+
|
|
|
+def mkassert(type, comp, lh, rh, size=None):
|
|
|
+ format = {
|
|
|
+ 'type': type.lower(), 'TYPE': type.upper(),
|
|
|
+ 'comp': comp.lower(), 'COMP': comp.upper(),
|
|
|
+ 'prefix': PREFIX.lower(), 'PREFIX': PREFIX.upper(),
|
|
|
+ 'lh': lh.strip(),
|
|
|
+ 'rh': rh.strip(),
|
|
|
+ 'size': size,
|
|
|
+ }
|
|
|
+ if size:
|
|
|
+ return ((ASSERT + '(__FILE__, __LINE__, {lh}, {rh}, {size})')
|
|
|
+ .format(**format))
|
|
|
else:
|
|
|
- return ''.join(ws) + ''.join(lh)
|
|
|
+ return ((ASSERT + '(__FILE__, __LINE__, {lh}, {rh})')
|
|
|
+ .format(**format))
|
|
|
+
|
|
|
+
|
|
|
+# simple recursive descent parser
|
|
|
+LEX = {
|
|
|
+ 'ws': [r'(?:\s|\n|#.*?\n|//.*?\n|/\*.*?\*/)+'],
|
|
|
+ 'assert': PATTERN,
|
|
|
+ 'string': [r'"(?:\\.|[^"])*"', r"'(?:\\.|[^'])\'"],
|
|
|
+ 'arrow': ['=>'],
|
|
|
+ 'paren': ['\(', '\)'],
|
|
|
+ 'op': ['strcmp', 'memcmp', '->'],
|
|
|
+ 'comp': ['==', '!=', '<=', '>=', '<', '>'],
|
|
|
+ 'logic': ['\&\&', '\|\|'],
|
|
|
+ 'sep': [':', ';', '\{', '\}', ','],
|
|
|
+}
|
|
|
+
|
|
|
+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 Parse:
|
|
|
+ def __init__(self, inf, lexemes):
|
|
|
+ p = '|'.join('(?P<%s>%s)' % (n, '|'.join(l))
|
|
|
+ for n, l in lexemes.items())
|
|
|
+ p = re.compile(p, re.DOTALL)
|
|
|
+ data = inf.read()
|
|
|
+ tokens = []
|
|
|
+ while True:
|
|
|
+ m = p.search(data)
|
|
|
+ if m:
|
|
|
+ if m.start() > 0:
|
|
|
+ tokens.append((None, data[:m.start()]))
|
|
|
+ tokens.append((m.lastgroup, m.group()))
|
|
|
+ data = data[m.end():]
|
|
|
+ else:
|
|
|
+ tokens.append((None, data))
|
|
|
+ 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 passert(p):
|
|
|
+ def pastr(p):
|
|
|
+ p.expect('assert') ; p.accept('ws') ; p.expect('(') ; p.accept('ws')
|
|
|
+ p.expect('strcmp') ; p.accept('ws') ; p.expect('(') ; p.accept('ws')
|
|
|
+ lh = pexpr(p) ; p.accept('ws')
|
|
|
+ p.expect(',') ; p.accept('ws')
|
|
|
+ rh = pexpr(p) ; p.accept('ws')
|
|
|
+ p.expect(')') ; p.accept('ws')
|
|
|
+ comp = p.expect('comp') ; p.accept('ws')
|
|
|
+ p.expect('0') ; p.accept('ws')
|
|
|
+ p.expect(')')
|
|
|
+ return mkassert('str', COMP[comp], lh, rh)
|
|
|
+
|
|
|
+ def pamem(p):
|
|
|
+ p.expect('assert') ; p.accept('ws') ; p.expect('(') ; p.accept('ws')
|
|
|
+ p.expect('memcmp') ; p.accept('ws') ; p.expect('(') ; p.accept('ws')
|
|
|
+ lh = pexpr(p) ; p.accept('ws')
|
|
|
+ p.expect(',') ; p.accept('ws')
|
|
|
+ rh = pexpr(p) ; p.accept('ws')
|
|
|
+ p.expect(',') ; p.accept('ws')
|
|
|
+ size = pexpr(p) ; p.accept('ws')
|
|
|
+ p.expect(')') ; p.accept('ws')
|
|
|
+ comp = p.expect('comp') ; p.accept('ws')
|
|
|
+ p.expect('0') ; p.accept('ws')
|
|
|
+ p.expect(')')
|
|
|
+ return mkassert('mem', COMP[comp], lh, rh, size)
|
|
|
+
|
|
|
+ def paint(p):
|
|
|
+ p.expect('assert') ; p.accept('ws') ; p.expect('(') ; p.accept('ws')
|
|
|
+ lh = pexpr(p) ; p.accept('ws')
|
|
|
+ comp = p.expect('comp') ; p.accept('ws')
|
|
|
+ rh = pexpr(p) ; p.accept('ws')
|
|
|
+ p.expect(')')
|
|
|
+ return mkassert('int', COMP[comp], lh, rh)
|
|
|
+
|
|
|
+ def pabool(p):
|
|
|
+ p.expect('assert') ; p.accept('ws') ; p.expect('(') ; p.accept('ws')
|
|
|
+ lh = pexprs(p) ; p.accept('ws')
|
|
|
+ p.expect(')')
|
|
|
+ return mkassert('bool', 'eq', lh, 'true')
|
|
|
+
|
|
|
+ def pa(p):
|
|
|
+ return p.expect('assert')
|
|
|
+
|
|
|
+ state = p.push()
|
|
|
+ lastf = None
|
|
|
+ for pa in [pastr, pamem, paint, pabool, pa]:
|
|
|
+ try:
|
|
|
+ return pa(p)
|
|
|
+ except ParseFailure as f:
|
|
|
+ p.pop(state)
|
|
|
+ lastf = f
|
|
|
+ else:
|
|
|
+ raise lastf
|
|
|
+
|
|
|
+def pexpr(p):
|
|
|
+ res = []
|
|
|
+ while True:
|
|
|
+ if p.accept('('):
|
|
|
+ res.append(p.m)
|
|
|
+ while True:
|
|
|
+ res.append(pexprs(p))
|
|
|
+ if p.accept('sep'):
|
|
|
+ res.append(p.m)
|
|
|
+ else:
|
|
|
+ break
|
|
|
+ res.append(p.expect(')'))
|
|
|
+ elif p.lookahead('assert'):
|
|
|
+ res.append(passert(p))
|
|
|
+ elif p.accept('assert', 'ws', 'string', 'op', None):
|
|
|
+ res.append(p.m)
|
|
|
+ else:
|
|
|
+ return ''.join(res)
|
|
|
+
|
|
|
+def pexprs(p):
|
|
|
+ res = []
|
|
|
+ while True:
|
|
|
+ res.append(pexpr(p))
|
|
|
+ if p.accept('comp', 'logic', ','):
|
|
|
+ res.append(p.m)
|
|
|
+ else:
|
|
|
+ return ''.join(res)
|
|
|
+
|
|
|
+def pstmt(p):
|
|
|
+ ws = p.accept('ws') or ''
|
|
|
+ lh = pexprs(p)
|
|
|
+ if p.accept('=>'):
|
|
|
+ rh = pexprs(p)
|
|
|
+ return ws + mkassert('int', 'eq', lh, rh)
|
|
|
+ else:
|
|
|
+ return ws + lh
|
|
|
|
|
|
-@p.generate
|
|
|
-def pstmts():
|
|
|
- a = yield pstmt
|
|
|
- b = yield (p.regex('[:;{}]') + pstmt).many()
|
|
|
- return [a] + b
|
|
|
|
|
|
def main(args):
|
|
|
inf = open(args.input, 'r') if args.input else sys.stdin
|
|
|
outf = open(args.output, 'w') if args.output else sys.stdout
|
|
|
|
|
|
- # parse C code
|
|
|
- input = inf.read()
|
|
|
- stmts = pstmts.parse(input)
|
|
|
+ lexemes = LEX.copy()
|
|
|
+ if args.pattern:
|
|
|
+ lexemes['assert'] = args.pattern
|
|
|
+ p = Parse(inf, lexemes)
|
|
|
|
|
|
# write extra verbose asserts
|
|
|
- outf.write("#include <stdbool.h>\n")
|
|
|
- outf.write("#include <stdint.h>\n")
|
|
|
- outf.write("#include <inttypes.h>\n")
|
|
|
- outf.write("#include <signal.h>\n")
|
|
|
- outf.write(mkdecl('int', 'eq', '=='))
|
|
|
- outf.write(mkdecl('int', 'ne', '!='))
|
|
|
- outf.write(mkdecl('int', 'lt', '<'))
|
|
|
- outf.write(mkdecl('int', 'gt', '>'))
|
|
|
- outf.write(mkdecl('int', 'le', '<='))
|
|
|
- outf.write(mkdecl('int', 'ge', '>='))
|
|
|
- outf.write(mkdecl('str', 'eq', '=='))
|
|
|
- outf.write(mkdecl('str', 'ne', '!='))
|
|
|
- outf.write(mkdecl('str', 'lt', '<'))
|
|
|
- outf.write(mkdecl('str', 'gt', '>'))
|
|
|
- outf.write(mkdecl('str', 'le', '<='))
|
|
|
- outf.write(mkdecl('str', 'ge', '>='))
|
|
|
- outf.write(mkdecl('bool', 'eq', '=='))
|
|
|
+ mkdecls(outf, maxwidth=args.maxwidth)
|
|
|
if args.input:
|
|
|
outf.write("#line %d \"%s\"\n" % (1, args.input))
|
|
|
|
|
|
- # write parsed statements
|
|
|
- for stmt in stmts:
|
|
|
- outf.write(stmt)
|
|
|
+ # parse and write out stmt at a time
|
|
|
+ try:
|
|
|
+ while True:
|
|
|
+ outf.write(pstmt(p))
|
|
|
+ if p.accept('sep'):
|
|
|
+ outf.write(p.m)
|
|
|
+ else:
|
|
|
+ break
|
|
|
+ except ParseFailure as f:
|
|
|
+ pass
|
|
|
+
|
|
|
+ for i in range(p.off, len(p.tokens)):
|
|
|
+ outf.write(p.tokens[i][1])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
import argparse
|
|
|
@@ -210,6 +374,10 @@ if __name__ == "__main__":
|
|
|
description="Cpp step that increases assert verbosity")
|
|
|
parser.add_argument('input', nargs='?',
|
|
|
help="Input C file after cpp.")
|
|
|
- parser.add_argument('-o', '--output',
|
|
|
+ parser.add_argument('-o', '--output', required=True,
|
|
|
help="Output C file.")
|
|
|
+ parser.add_argument('-p', '--pattern', action='append',
|
|
|
+ help="Patterns to search for starting an assert statement.")
|
|
|
+ parser.add_argument('--maxwidth', default=MAXWIDTH, type=int,
|
|
|
+ help="Maximum number of characters to display for strcmp and memcmp.")
|
|
|
main(parser.parse_args())
|