2 #---------------------------------------------------------------------------
3 # valdiag.py - Validate diagnostic messages from SDCC/GCC
4 # Written By - Erik Petrich . epetrich@users.sourceforge.net (2003)
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the
8 # Free Software Foundation; either version 2, or (at your option) any
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 # In other words, you are welcome to use, share and improve this program.
21 # You are forbidden to forbid anyone else to use, share and improve
22 # what you give them. Help stamp out software-hoarding!
23 #---------------------------------------------------------------------------
25 import sys, string, os, popen2, re
43 "CC":"../../bin/sdcc",
44 "CCFLAGS":"-c -m{port}",
53 "code not generated.*due to previous errors",
54 "unreferenced function argument"
73 "flags":"--model-large",
75 "SDCC_MODEL_LARGE":"1"
81 "flags":"--stack-auto",
113 def evalQualifier(expr):
115 tokens = re.split("([^0-9A-Za-z_])", expr)
116 for tokenindex in range(len(tokens)):
117 token = tokens[tokenindex]
118 if token in macrodefs:
119 tokens[tokenindex] = macrodefs[token]
120 elif token == "defined":
121 tokens[tokenindex] = ""
122 if tokens[tokenindex+2] in macrodefs:
123 tokens[tokenindex+2] = "1"
125 tokens[tokenindex+2] = "0"
127 if token[0]=="_" or token[0] in string.ascii_letters:
128 tokens[tokenindex] = "0"
129 expr = string.join(tokens,"")
130 expr = string.replace(expr,"&&"," and ");
131 expr = string.replace(expr,"||"," or ");
132 expr = string.replace(expr,"!"," not ");
135 def expandPyExpr(expr):
136 tokens = re.split("({|})", expr)
137 for tokenindex in range(1,len(tokens)):
138 if tokens[tokenindex-1]=="{":
139 tokens[tokenindex]=eval(tokens[tokenindex])
140 tokens[tokenindex-1]=""
141 tokens[tokenindex+1]=""
142 expandedExpr = string.join(tokens,"")
145 def addDefines(deflist):
146 for define in deflist.keys():
147 expandeddef = expandPyExpr(define)
148 macrodefs[expandeddef] = expandPyExpr(deflist[define])
150 def parseInputfile(inputfilename):
151 inputfile = open(inputfilename, "r")
156 # Find the test cases and tests in this file
157 for line in inputfile.readlines():
159 # See if a new testcase is being defined
160 p = string.find(line, "TEST")
162 testname = string.split(line[p:])[0]
163 if not testcases.has_key(testname):
164 testcases[testname] = {}
166 # See if a new test is being defined
167 for testtype in ["ERROR", "WARNING", "IGNORE"]:
168 p = string.find(line, testtype);
170 # Found a test definition
171 qualifier = string.strip(line[p+len(testtype):])
172 p = string.find(qualifier, "*/")
174 qualifier = string.strip(qualifier[:p])
175 if len(qualifier)==0:
177 qualifier = evalQualifier(qualifier)
179 if not linenumber in testcases[testname]:
180 testcases[testname][linenumber]=[]
181 testcases[testname][linenumber].append(testtype)
183 linenumber = linenumber + 1
188 def parseResults(output):
193 if string.count(line, "SIGSEG"):
194 results[0] = ["FAULT", string.strip(line)]
197 # look for something of the form:
198 # filename:line:message
199 msg = string.split(line,":",2)
200 if len(msg)<3: continue
201 if msg[0]!=inputfilename: continue
202 if len(msg[1])==0: continue
203 if not msg[1][0] in string.digits: continue
205 # it's in the right form; parse it
206 linenumber = int(msg[1])
208 uppermsg = string.upper(msg[2])
209 if string.count(uppermsg,"ERROR"):
211 if string.count(uppermsg,"WARNING"):
213 msgtext = string.strip(msg[2])
215 for ignoreExpr in ignoreExprList:
216 if re.search(ignoreExpr,msgtext)!=None:
219 results[linenumber]=[msgtype,string.strip(msg[2])]
223 print "Usage: test testmode cfile [objectfile]"
224 print "Choices for testmode are:"
225 for testmodename in testmodes.keys():
226 print " %s" % testmodename
233 testmodename = sys.argv[1]
234 if not testmodename in testmodes:
235 print "Unknown test mode '%s'" % testmodename
238 testmode = testmodes[testmodename]
239 compilermode = testmode["compiler"]
240 port = expandPyExpr(testmode["port"])
241 cc = expandPyExpr(compilermode["CC"])
242 ccflags = expandPyExpr(compilermode["CCFLAGS"])
243 if "flags" in testmode:
244 ccflags = string.join([ccflags,expandPyExpr(testmode["flags"])])
246 if "CCOUTPUT" in compilermode:
247 ccflags = string.join([ccflags,expandPyExpr(compilermode["CCOUTPUT"]),sys.argv[3]])
248 if "defined" in compilermode:
249 addDefines(compilermode["defined"])
250 if "defined" in testmode:
251 addDefines(testmode["defined"])
252 if "ignoremsg" in compilermode:
253 ignoreExprList = compilermode["ignoremsg"]
257 inputfilename = sys.argv[2]
259 testcases = parseInputfile(inputfilename)
261 print "Unable to read file '%s'" % inputfilename
264 casecount = len(testcases.keys())
268 for testname in testcases.keys():
269 ccdef = compilermode["CCDEF"]+testname
270 cmd = string.join([cc,ccflags,ccdef,inputfilename])
273 spawn = popen2.Popen4(cmd)
275 output = spawn.fromchild.readlines()
277 results = parseResults(output)
279 if len(testcases[testname])==0:
280 testcount = testcount + 1 #implicit test for no errors
282 # Go through the tests of this case and make sure
283 # the compiler gave a diagnostic
284 for checkline in testcases[testname].keys():
285 testcount = testcount + 1
286 if checkline in results:
287 if "IGNORE" in testcases[testname][checkline]:
288 testcount = testcount - 1 #this isn't really a test
289 del results[checkline]
291 for wanted in testcases[testname][checkline]:
292 if not wanted=="IGNORE":
293 print "--- FAIL: expected %s" % wanted,
294 print "at %s:%d" % (inputfilename, checkline)
295 failurecount = failurecount + 1
297 # Output any unexpected diagnostics
298 for checkline in results.keys():
299 print '--- FAIL: unexpected message "%s" ' % results[checkline][1],
300 print "at %s:%d" % (inputfilename, checkline)
301 failurecount = failurecount + 1
304 print "--- Summary: %d/%d/%d: " % (failurecount, testcount, casecount),
305 print "%d failed of %d tests in %d cases." % (failurecount, testcount, casecount)