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
31 "CCFLAGS":"-c -Wall -DPORT_HOST=1",
45 "CC":"../../bin/sdcc",
46 "CCFLAGS":"-c -m{port}",
57 "code not generated.*due to previous errors",
58 "unreferenced function argument"
77 "flags":"--model-large",
79 "SDCC_MODEL_LARGE":"1"
85 "flags":"--stack-auto",
117 def evalQualifier(expr):
119 tokens = re.split("([^0-9A-Za-z_])", expr)
120 for tokenindex in range(len(tokens)):
121 token = tokens[tokenindex]
122 if token in macrodefs:
123 tokens[tokenindex] = macrodefs[token]
124 elif token == "defined":
125 tokens[tokenindex] = ""
126 if tokens[tokenindex+2] in macrodefs:
127 tokens[tokenindex+2] = "1"
129 tokens[tokenindex+2] = "0"
131 if token[0]=="_" or token[0] in string.ascii_letters:
132 tokens[tokenindex] = "0"
133 expr = string.join(tokens,"")
134 expr = string.replace(expr,"&&"," and ");
135 expr = string.replace(expr,"||"," or ");
136 expr = string.replace(expr,"!"," not ");
139 def expandPyExpr(expr):
140 tokens = re.split("({|})", expr)
141 for tokenindex in range(1,len(tokens)):
142 if tokens[tokenindex-1]=="{":
143 tokens[tokenindex]=eval(tokens[tokenindex])
144 tokens[tokenindex-1]=""
145 tokens[tokenindex+1]=""
146 expandedExpr = string.join(tokens,"")
149 def addDefines(deflist):
150 for define in deflist.keys():
151 expandeddef = expandPyExpr(define)
152 macrodefs[expandeddef] = expandPyExpr(deflist[define])
154 def parseInputfile(inputfilename):
155 inputfile = open(inputfilename, "r")
160 # Find the test cases and tests in this file
161 for line in inputfile.readlines():
163 # See if a new testcase is being defined
164 p = string.find(line, "TEST")
166 testname = string.split(line[p:])[0]
167 if not testcases.has_key(testname):
168 testcases[testname] = {}
170 # See if a new test is being defined
171 for testtype in ["ERROR", "WARNING", "IGNORE"]:
172 p = string.find(line, testtype);
174 # Found a test definition
175 qualifier = string.strip(line[p+len(testtype):])
176 p = string.find(qualifier, "*/")
178 qualifier = string.strip(qualifier[:p])
179 if len(qualifier)==0:
181 qualifier = evalQualifier(qualifier)
183 if not linenumber in testcases[testname]:
184 testcases[testname][linenumber]=[]
185 testcases[testname][linenumber].append(testtype)
187 linenumber = linenumber + 1
192 def parseResults(output):
197 if string.count(line, "SIGSEG"):
198 results[0] = ["FAULT", string.strip(line)]
201 # look for something of the form:
202 # filename:line:message
203 msg = string.split(line,":",2)
204 if len(msg)<3: continue
205 if msg[0]!=inputfilename: continue
206 if len(msg[1])==0: continue
207 if not msg[1][0] in string.digits: continue
209 # it's in the right form; parse it
210 linenumber = int(msg[1])
212 uppermsg = string.upper(msg[2])
213 if string.count(uppermsg,"ERROR"):
215 if string.count(uppermsg,"WARNING"):
217 msgtext = string.strip(msg[2])
219 for ignoreExpr in ignoreExprList:
220 if re.search(ignoreExpr,msgtext)!=None:
223 results[linenumber]=[msgtype,string.strip(msg[2])]
227 print "Usage: test testmode cfile [objectfile]"
228 print "Choices for testmode are:"
229 for testmodename in testmodes.keys():
230 print " %s" % testmodename
237 testmodename = sys.argv[1]
238 if not testmodename in testmodes:
239 print "Unknown test mode '%s'" % testmodename
242 testmode = testmodes[testmodename]
243 compilermode = testmode["compiler"]
244 port = expandPyExpr(testmode["port"])
245 cc = expandPyExpr(compilermode["CC"])
246 ccflags = expandPyExpr(compilermode["CCFLAGS"])
247 if "flags" in testmode:
248 ccflags = string.join([ccflags,expandPyExpr(testmode["flags"])])
250 if "CCOUTPUT" in compilermode:
251 ccflags = string.join([ccflags,expandPyExpr(compilermode["CCOUTPUT"]),sys.argv[3]])
252 if "defined" in compilermode:
253 addDefines(compilermode["defined"])
254 if "defined" in testmode:
255 addDefines(testmode["defined"])
256 if "ignoremsg" in compilermode:
257 ignoreExprList = compilermode["ignoremsg"]
261 inputfilename = sys.argv[2]
263 testcases = parseInputfile(inputfilename)
265 print "Unable to read file '%s'" % inputfilename
268 casecount = len(testcases.keys())
272 for testname in testcases.keys():
273 ccdef = compilermode["CCDEF"]+testname
274 if testname[-3:] == "C89":
275 ccstd = compilermode["C89"]
276 elif testname[-3:] == "C99":
277 ccstd = compilermode["C99"]
280 cmd = string.join([cc,ccflags,ccstd,ccdef,inputfilename])
283 spawn = popen2.Popen4(cmd)
285 output = spawn.fromchild.readlines()
287 results = parseResults(output)
289 if len(testcases[testname])==0:
290 testcount = testcount + 1 #implicit test for no errors
292 # Go through the tests of this case and make sure
293 # the compiler gave a diagnostic
294 for checkline in testcases[testname].keys():
295 testcount = testcount + 1
296 if checkline in results:
297 if "IGNORE" in testcases[testname][checkline]:
298 testcount = testcount - 1 #this isn't really a test
299 del results[checkline]
301 for wanted in testcases[testname][checkline]:
302 if not wanted=="IGNORE":
303 print "--- FAIL: expected %s" % wanted,
304 print "at %s:%d" % (inputfilename, checkline)
305 failurecount = failurecount + 1
307 # Output any unexpected diagnostics
308 for checkline in results.keys():
309 print '--- FAIL: unexpected message "%s" ' % results[checkline][1],
310 print "at %s:%d" % (inputfilename, checkline)
311 failurecount = failurecount + 1
314 print "--- Summary: %d/%d/%d: " % (failurecount, testcount, casecount),
315 print "%d failed of %d tests in %d cases." % (failurecount, testcount, casecount)