X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=build-aux%2Fextract-ofp-errors;h=c3273041404ca8c1a8b650f81168b6703a947781;hb=2e1ae2005ed347d2dfebd23fff40c54a1a2a6716;hp=c34888fc9aad7f5676c0a4a02d2f6ff2a7b421e9;hpb=dc4762edd02693770d392b8f6495deb7e52635bf;p=openvswitch diff --git a/build-aux/extract-ofp-errors b/build-aux/extract-ofp-errors index c34888fc..c3273041 100755 --- a/build-aux/extract-ofp-errors +++ b/build-aux/extract-ofp-errors @@ -12,6 +12,15 @@ idRe = "[a-zA-Z_][a-zA-Z_0-9]*" tokenRe = "#?" + idRe + "|[0-9]+|." inComment = False inDirective = False + +def getLine(): + global line + global lineNumber + line = inputFile.readline() + lineNumber += 1 + if line == "": + fatal("unexpected end of input") + def getToken(): global token global line @@ -57,8 +66,14 @@ def getToken(): token = None return False +n_errors = 0 +def error(msg): + global n_errors + sys.stderr.write("%s:%d: %s\n" % (fileName, lineNumber, msg)) + n_errors += 1 + def fatal(msg): - sys.stderr.write("%s:%d: error at \"%s\": %s\n" % (fileName, lineNumber, token, msg)) + error(msg) sys.exit(1) def skipDirective(): @@ -124,95 +139,243 @@ This program reads the header files specified on the command line and outputs a C source file for translating OpenFlow error codes into strings, for use as lib/ofp-errors.c in the Open vSwitch source tree. -This program is specialized for reading include/openflow/openflow.h -and include/openflow/nicira-ext.h. It will not work on arbitrary -header files without extensions.''' % {"argv0": argv0} +This program is specialized for reading lib/ofp-errors.h. It will not +work on arbitrary header files without extensions.\ +''' % {"argv0": argv0} sys.exit(0) def extract_ofp_errors(filenames): error_types = {} + comments = [] + names = [] + domain = {} + reverse = {} + for domain_name in ("OF1.0", "OF1.1", "OF1.2", "OF1.3", + "NX1.0", "NX1.1", "NX1.2", "NX1.3"): + domain[domain_name] = {} + reverse[domain_name] = {} + + n_errors = 0 + expected_errors = {} + global fileName for fileName in filenames: global inputFile global lineNumber inputFile = open(fileName) lineNumber = 0 - while getToken(): - if token in ("#ifdef", "#ifndef", "#include", - "#endif", "#elif", "#else", '#define'): - skipDirective() - elif match('enum'): - forceId() - enum_tag = token - getToken() - - forceMatch("{") - - constants = [] - while isId(token): - constants.append(token) - getToken() - if match('='): - while token != ',' and token != '}': - getToken() - match(',') - - forceMatch('}') - - if enum_tag == "ofp_error_type": - error_types = {} - for error_type in constants: - error_types[error_type] = [] - elif enum_tag == 'nx_vendor_code': - pass - elif enum_tag.endswith('_code'): - error_type = 'OFPET_%s' % '_'.join(enum_tag.split('_')[1:-1]).upper() - if error_type not in error_types: - fatal("enum %s looks like an error code enumeration but %s is unknown" % (enum_tag, error_type)) - error_types[error_type] += constants - elif token in ('struct', 'union'): - getToken() - forceId() - getToken() - forceMatch('{') - while not match('}'): - getToken() - elif match('OFP_ASSERT') or match('BOOST_STATIC_ASSERT'): - while token != ';': - getToken() - else: - fatal("parse error") + + while True: + getLine() + if re.match('enum ofperr', line): + break + + while True: + getLine() + if line.startswith('/*') or not line or line.isspace(): + continue + elif re.match('}', line): + break + + if not line.lstrip().startswith('/*'): + fatal("unexpected syntax between errors") + + comment = line.lstrip()[2:].strip() + while not comment.endswith('*/'): + getLine() + if line.startswith('/*') or not line or line.isspace(): + fatal("unexpected syntax within error") + comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n') + comment = comment[:-2].rstrip() + + m = re.match('Expected: (.*)\.$', comment) + if m: + expected_errors[m.group(1)] = (fileName, lineNumber) + continue + + m = re.match('((?:.(?!\. ))+.)\. (.*)$', comment) + if not m: + fatal("unexpected syntax between errors") + + dsts, comment = m.groups() + + getLine() + m = re.match('\s+(?:OFPERR_((?:OFP|NX)[A-Z0-9_]+))(\s*=\s*OFPERR_OFS)?,', + line) + if not m: + fatal("syntax error expecting enum value") + + enum = m.group(1) + + comments.append(re.sub('\[[^]]*\]', '', comment)) + names.append(enum) + + for dst in dsts.split(', '): + m = re.match(r'([A-Z0-9.+]+)\((\d+|(0x)[0-9a-fA-F]+)(?:,(\d+))?\)$', dst) + if not m: + fatal("%s: syntax error in destination" % dst) + targets = m.group(1) + if m.group(3): + base = 16 + else: + base = 10 + type_ = int(m.group(2), base) + if m.group(4): + code = int(m.group(4)) + else: + code = None + + target_map = {"OF1.0+": ("OF1.0", "OF1.1", "OF1.2", "OF1.3"), + "OF1.1+": ("OF1.1", "OF1.2", "OF1.3"), + "OF1.2+": ("OF1.2", "OF1.3"), + "OF1.3+": ("OF1.3",), + "OF1.0": ("OF1.0",), + "OF1.1": ("OF1.1",), + "OF1.2": ("OF1.2",), + "OF1.3": ("OF1.3",), + "NX1.0+": ("OF1.0", "OF1.1", "OF1.2", "OF1.3"), + "NX1.1+": ("OF1.1", "OF1.2", "OF1.3"), + "NX1.2+": ("OF1.2", "OF1.3"), + "NX1.3+": ("OF1.3",), + "NX1.0": ("OF1.0",), + "NX1.1": ("OF1.1",), + "NX1.2": ("OF1.2",), + "NX1.3": ("OF1.3",)} + if targets not in target_map: + fatal("%s: unknown error domain" % targets) + if targets.startswith('NX') and code < 0x100: + fatal("%s: NX domain code cannot be less than 0x100" % dst) + if targets.startswith('OF') and code >= 0x100: + fatal("%s: OF domain code cannot be greater than 0x100" + % dst) + for target in target_map[targets]: + domain[target].setdefault(type_, {}) + if code in domain[target][type_]: + msg = "%d,%d in %s means both %s and %s" % ( + type_, code, target, + domain[target][type_][code][0], enum) + if msg in expected_errors: + del expected_errors[msg] + else: + error("%s: %s." % (dst, msg)) + sys.stderr.write("%s:%d: %s: Here is the location " + "of the previous definition.\n" + % (domain[target][type_][code][1], + domain[target][type_][code][2], + dst)) + else: + domain[target][type_][code] = (enum, fileName, + lineNumber) + + if enum in reverse[target]: + error("%s: %s in %s means both %d,%d and %d,%d." % + (dst, enum, target, + reverse[target][enum][0], + reverse[target][enum][1], + type_, code)) + reverse[target][enum] = (type_, code) + inputFile.close() - print "/* -*- buffer-read-only: t -*- */" - print "#include " - print '#include "ofp-errors.h"' - print "#include " - print "#include " - for fileName in sys.argv[1:]: - print '#include "%s"' % fileName - print '#include "type-props.h"' - - for error_type, constants in sorted(error_types.items()): - tag = 'ofp_%s_code' % re.sub('^OFPET_', '', error_type).lower() - print_enum(tag, constants, "static ") - print_enum("ofp_error_type", error_types.keys(), "") - print """ -const char * -ofp_error_code_to_string(uint16_t type, uint16_t code) -{ - switch (type) {\ -""" - for error_type in error_types: - tag = 'ofp_%s_code' % re.sub('^OFPET_', '', error_type).lower() - print " case %s:" % error_type - print " return %s_to_string(code);" % tag + for fn, ln in expected_errors.itervalues(): + sys.stderr.write("%s:%d: expected duplicate not used.\n" % (fn, ln)) + n_errors += 1 + + if n_errors: + sys.exit(1) + print """\ +/* Generated automatically; do not modify! -*- buffer-read-only: t -*- */ + +#define OFPERR_N_ERRORS %d + +struct ofperr_domain { + const char *name; + uint8_t version; + enum ofperr (*decode)(uint16_t type, uint16_t code); + enum ofperr (*decode_type)(uint16_t type); + struct pair errors[OFPERR_N_ERRORS]; +}; + +static const char *error_names[OFPERR_N_ERRORS] = { +%s +}; + +static const char *error_comments[OFPERR_N_ERRORS] = { +%s +};\ +""" % (len(names), + '\n'.join(' "%s",' % name for name in names), + '\n'.join(' "%s",' % re.sub(r'(["\\])', r'\\\1', comment) + for comment in comments)) + + def output_domain(map, name, description, version): + print """ +static enum ofperr +%s_decode(uint16_t type, uint16_t code) +{ + switch ((type << 16) | code) {""" % name + found = set() + for enum in names: + if enum not in map: + continue + type_, code = map[enum] + if code is None: + continue + value = (type_ << 16) | code + if value in found: + continue + found.add(value) + print " case (%d << 16) | %d:" % (type_, code) + print " return OFPERR_%s;" % enum + print """\ } - return NULL; -}\ -""" + + return 0; +} + +static enum ofperr +%s_decode_type(uint16_t type) +{ + switch (type) {""" % name + for enum in names: + if enum not in map: + continue + type_, code = map[enum] + if code is not None: + continue + print " case %d:" % type_ + print " return OFPERR_%s;" % enum + print """\ + } + + return 0; +}""" + + print """ +static const struct ofperr_domain %s = { + "%s", + %d, + %s_decode, + %s_decode_type, + {""" % (name, description, version, name, name) + for enum in names: + if enum in map: + type_, code = map[enum] + if code == None: + code = -1 + else: + type_ = code = -1 + print " { %2d, %3d }, /* %s */" % (type_, code, enum) + print """\ + }, +};""" + + output_domain(reverse["OF1.0"], "ofperr_of10", "OpenFlow 1.0", 0x01) + output_domain(reverse["OF1.1"], "ofperr_of11", "OpenFlow 1.1", 0x02) + output_domain(reverse["OF1.2"], "ofperr_of12", "OpenFlow 1.2", 0x03) + output_domain(reverse["OF1.3"], "ofperr_of13", "OpenFlow 1.3", 0x04) if __name__ == '__main__': if '--help' in sys.argv: