diff --git a/Tools/bgen/bgen/scantools.py b/Tools/bgen/bgen/scantools.py index 06d606b8370..e6f9b9ad6b8 100644 --- a/Tools/bgen/bgen/scantools.py +++ b/Tools/bgen/bgen/scantools.py @@ -61,7 +61,7 @@ class Scanner: def initblacklists(self): self.blacklistnames = self.makeblacklistnames() - self.blacklisttypes = ["unknown"] + self.makeblacklisttypes() + self.blacklisttypes = ["unknown", "-"] + self.makeblacklisttypes() def makeblacklistnames(self): return [] @@ -73,7 +73,103 @@ class Scanner: self.repairinstructions = self.makerepairinstructions() def makerepairinstructions(self): - return [] + """Parse the repair file into repair instructions. + + The file format is simple: + 1) use \ to split a long logical line in multiple physical lines + 2) everything after the first # on a line is ignored (as comment) + 3) empty lines are ignored + 4) remaining lines must have exactly 3 colon-separated fields: + functionpattern : argumentspattern : argumentsreplacement + 5) all patterns use shell style pattern matching + 6) an empty functionpattern means the same as * + 7) the other two fields are each comma-separated lists of triples + 8) a triple is a space-separated list of 1-3 words + 9) a triple with less than 3 words is padded at the end with "*" words + 10) when used as a pattern, a triple matches the type, name, and mode + of an argument, respectively + 11) when used as a replacement, the words of a triple specify + replacements for the corresponding words of the argument, + with "*" as a word by itself meaning leave the original word + (no other uses of "*" is allowed) + 12) the replacement need not have the same number of triples + as the pattern + """ + f = self.openrepairfile() + if not f: return [] + print "Reading repair file", `f.name`, "..." + list = [] + lineno = 0 + while 1: + line = f.readline() + if not line: break + lineno = lineno + 1 + startlineno = lineno + while line[-2:] == '\\\n': + line = line[:-2] + ' ' + f.readline() + lineno = lineno + 1 + i = string.find(line, '#') + if i >= 0: line = line[:i] + words = map(string.strip, string.splitfields(line, ':')) + if words == ['']: continue + if len(words) <> 3: + print "Line", startlineno, + print ": bad line (not 3 colon-separated fields)" + print `line` + continue + [fpat, pat, rep] = words + if not fpat: fpat = "*" + if not pat: + print "Line", startlineno, + print "Empty pattern" + print `line` + continue + patparts = map(string.strip, string.splitfields(pat, ',')) + repparts = map(string.strip, string.splitfields(rep, ',')) + patterns = [] + for p in patparts: + if not p: + print "Line", startlineno, + print "Empty pattern part" + print `line` + continue + pattern = string.split(p) + if len(pattern) > 3: + print "Line", startlineno, + print "Pattern part has > 3 words" + print `line` + pattern = pattern[:3] + else: + while len(pattern) < 3: + pattern.append("*") + patterns.append(pattern) + replacements = [] + for p in repparts: + if not p: + print "Line", startlineno, + print "Empty replacement part" + print `line` + continue + replacement = string.split(p) + if len(replacement) > 3: + print "Line", startlineno, + print "Pattern part has > 3 words" + print `line` + replacement = replacement[:3] + else: + while len(replacement) < 3: + replacement.append("*") + replacements.append(replacement) + list.append((fpat, patterns, replacements)) + return list + + def openrepairfile(self, filename = "REPAIR"): + try: + return open(filename, "r") + except IOError, msg: + print `filename`, ":", msg + print "Cannot open repair file -- assume no repair needed" + return None def initfiles(self): self.specmine = 0 @@ -90,11 +186,13 @@ class Scanner: def initpatterns(self): self.head_pat = "^pascal[ \t]+" # XXX Mac specific! - self.tail_pat = "[);]" - self.whole_pat = "\([a-zA-Z0-9_]+\)[ \t\n]+" + \ - "\([a-zA-Z0-9_]+\)[ \t\n]*(\([^()]*\))" + self.tail_pat = "[;={}]" + self.type_pat = "pascal[ \t\n]+\([a-zA-Z0-9_]+\)[ \t\n]+" + self.name_pat = "\([a-zA-Z0-9_]+\)[ \t\n]*" + self.args_pat = "(\(\([^(;=)]+\|([^(;=)]*)\)*\))" + self.whole_pat = self.type_pat + self.name_pat + self.args_pat self.sym_pat = "^[ \t]*\([a-zA-Z0-9_]+\)[ \t]*=" + \ - "[ \t]*\([-0-9'\"][^\t\n,}]*\),?" + "[ \t]*\([-0-9'\"][^\t\n,;}]*\),?" self.asplit_pat = "^\(.*[^a-zA-Z0-9_]\)\([a-zA-Z0-9_]+\)$" def compilepatterns(self): @@ -212,12 +310,12 @@ class Scanner: self.report("(No interface specifications will be written)") else: self.report("specfile = %s", `self.specfile.name`) - self.specfile.write("# Generated from %s\n" % `inputname`) + self.specfile.write("# Generated from %s\n\n" % `inputname`) if not self.defsfile: self.report("(No symbol definitions will be written)") else: self.report("defsfile = %s", `self.defsfile.name`) - self.defsfile.write("# Generated from %s\n" % `inputname`) + self.defsfile.write("# Generated from %s\n\n" % `inputname`) self.alreadydone = [] try: while 1: @@ -237,7 +335,7 @@ class Scanner: self.defsfile.write("%s = %s\n" % (name, defn)) def dofuncspec(self): - raw = self.line[len(self.head.group(0)):] + raw = self.line while self.tail.search(raw) < 0: line = self.getline() raw = raw + line @@ -256,7 +354,7 @@ class Scanner: self.error("*** %s %s blacklisted", type, name) return arglist = self.extractarglist(args) - arglist = self.repairarglist(arglist) + arglist = self.repairarglist(name, arglist) if self.unmanageable(type, name, arglist): ##for arg in arglist: ## self.report(" %s", `arg`) @@ -285,18 +383,30 @@ class Scanner: type = regsub.gsub("\*", " ptr ", type) type = string.strip(type) type = regsub.gsub("[ \t]+", "_", type) + return self.modifyarg(type, name, mode) + + def modifyarg(self, type, name, mode): if type[:6] == "const_": type = type[6:] elif type[-4:] == "_ptr": type = type[:-4] mode = "OutMode" + if type[-4:] == "_far": + type = type[:-4] return type, name, mode - def repairarglist(self, arglist): + def repairarglist(self, functionname, arglist): arglist = arglist[:] i = 0 while i < len(arglist): - for pattern, replacement in self.repairinstructions: + for item in self.repairinstructions: + if len(item) == 2: + pattern, replacement = item + functionpat = "*" + else: + functionpat, pattern, replacement = item + if not fnmatch.fnmatchcase(functionname, functionpat): + continue n = len(pattern) if i+n > len(arglist): continue current = arglist[i:i+n] @@ -336,12 +446,12 @@ class Scanner: def generate(self, type, name, arglist): classname, listname = self.destination(type, name, arglist) if not self.specfile: return - self.specfile.write("\nf = %s(%s, %s,\n" % (classname, type, `name`)) + self.specfile.write("f = %s(%s, %s,\n" % (classname, type, `name`)) for atype, aname, amode in arglist: self.specfile.write(" (%s, %s, %s),\n" % (atype, `aname`, amode)) self.specfile.write(")\n") - self.specfile.write("%s.append(f)\n" % listname) + self.specfile.write("%s.append(f)\n\n" % listname) def destination(self, type, name, arglist): return "FunctionGenerator", "functions"