A python script to validate compiler diagnostic messages. It can be
authorepetrich <epetrich@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Tue, 6 Jan 2004 07:14:55 +0000 (07:14 +0000)
committerepetrich <epetrich@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Tue, 6 Jan 2004 07:14:55 +0000 (07:14 +0000)
used to verify that sdcc complains about bad c source code and
gives a good location of the error.
* support/valdiag/Makefile,
* support/valdiag/valdiag.py,
* support/valdiag/tests/*

git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@3086 4a8a32a2-be11-0410-ad9d-d568d2c75423

12 files changed:
ChangeLog
support/valdiag/Makefile [new file with mode: 0644]
support/valdiag/tests/cflow.c [new file with mode: 0644]
support/valdiag/tests/const.c [new file with mode: 0644]
support/valdiag/tests/enum.c [new file with mode: 0644]
support/valdiag/tests/funcdec.c [new file with mode: 0644]
support/valdiag/tests/primtypes.c [new file with mode: 0644]
support/valdiag/tests/struct.c [new file with mode: 0644]
support/valdiag/tests/switch.c [new file with mode: 0644]
support/valdiag/tests/tentdecl.c [new file with mode: 0644]
support/valdiag/tests/typedef.c [new file with mode: 0644]
support/valdiag/valdiag.py [new file with mode: 0644]

index 2189e0d349edc5c10c01a94f6f56250148e3d79d..3c48f3ea4dd3fe1e75c9851ad5c357e05e3891bb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2004-01-06 Erik Petrich <epetrich@ivorytower.norman.ok.us>
+
+       A python script to validate compiler diagnostic messages. It can be
+       used to verify that sdcc complains about bad c source code and
+       gives a good location of the error.
+       * support/valdiag/Makefile,
+       * support/valdiag/valdiag.py,
+       * support/valdiag/tests/*
+
 2004-01-06 Erik Petrich <epetrich@ivorytower.norman.ok.us>
 
        * src/SDCC.y (enum_specifier, enumerator_list, opt_assign_expr),
diff --git a/support/valdiag/Makefile b/support/valdiag/Makefile
new file mode 100644 (file)
index 0000000..12c61c1
--- /dev/null
@@ -0,0 +1,45 @@
+.SILENT:
+
+TESTS_DIR = tests
+RESULTS_DIR = results
+PORTS_DIR = ports
+BUILD_DIR = gen
+ALL_PORTS = host mcs51 mcs51-large mcs51-stack-auto ds390 z80 hc08
+
+ALL_TESTS = $(shell find $(TESTS_DIR) -name "*.c")
+
+PORT_RESULTS_DIR = $(RESULTS_DIR)/$(PORT)
+PORT_RESULTS = $(ALL_TESTS:$(TESTS_DIR)/%.c=$(PORT_RESULTS_DIR)/%.out)
+PORT_BUILD_DIR = $(BUILD_DIR)/$(PORT)
+
+all: test-ports
+
+test-ports:
+       for i in $(ALL_PORTS); do $(MAKE) test-port PORT=$$i; done
+
+test-mcs51:
+       $(MAKE) test-port PORT=mcs51
+        
+test-port: port-results
+
+clean: clean-gen
+       rm -rf $(RESULTS_DIR) *.pyc
+       rm -rf $(BUILD_DIR)
+
+clean-gen:     
+       for i in $(ALL_PORTS); do $(MAKE) clean-port PORT=$$i; done
+
+clean-port:
+       rm -rf $(PORT_BUILD_DIR)
+
+$(PORT_RESULTS_DIR)/%.out: $(TESTS_DIR)/%.c
+       echo Processing $<
+       python valdiag.py $(PORT) $< $(PORT_BUILD_DIR)/$* > $@
+
+port-results: port-dirs $(PORT_RESULTS)
+       echo Summary for \'$(PORT)\': `cat $(PORT_RESULTS) | \
+       python ../regression/collate-results.py`
+
+port-dirs:
+       mkdir -p $(PORT_RESULTS_DIR)
+       mkdir -p $(PORT_BUILD_DIR)
diff --git a/support/valdiag/tests/cflow.c b/support/valdiag/tests/cflow.c
new file mode 100644 (file)
index 0000000..b584550
--- /dev/null
@@ -0,0 +1,26 @@
+
+int x;
+
+#ifdef TEST0
+void foo(void)
+{
+  while (1) ;
+}
+#endif
+
+#ifdef TEST1
+void foo(void)
+{
+  while (1) ;
+  x++;         /* WARNING(SDCC) */
+}
+#endif
+
+#ifdef TEST2
+void foo(void)
+{
+  int y=1;
+  while (y) ;  /* WARNING(SDCC) */
+  x++;         /* WARNING(SDCC) */
+}
+#endif
diff --git a/support/valdiag/tests/const.c b/support/valdiag/tests/const.c
new file mode 100644 (file)
index 0000000..5082081
--- /dev/null
@@ -0,0 +1,21 @@
+
+char a;
+const char ca=2;
+const char *pca;
+char * const cpa=&a;
+
+void test(void)
+{
+  a = 1;
+#ifdef TEST1
+  ca = a;              /* ERROR */
+#endif
+#ifdef TEST2
+  pca = &a;
+  *pca = 2;            /* ERROR */
+#endif
+#ifdef TEST3
+  *cpa = 3;
+  cpa = &ca;           /* ERROR */
+#endif
+}
diff --git a/support/valdiag/tests/enum.c b/support/valdiag/tests/enum.c
new file mode 100644 (file)
index 0000000..78eeb00
--- /dev/null
@@ -0,0 +1,89 @@
+
+#ifdef TEST1
+enum tag
+{
+  first,
+  second,
+  third
+};
+#endif
+
+#ifdef TEST2
+enum tag
+{
+  first,       /* IGNORE */
+  second,
+  third,
+  first,       /* ERROR */
+  fourth
+};
+#endif
+
+
+#ifdef TEST3
+enum
+{
+  first,       /* IGNORE */
+  second,
+  third,
+  first,       /* ERROR */
+  fourth
+};
+#endif
+
+
+#ifdef TEST4
+enum
+{
+  first=1,
+  second,
+  third,
+};
+#endif
+
+
+#ifdef TEST5
+enum
+{
+  first=1.1,   /* ERROR */
+  second,
+  third,
+};
+#endif
+
+#ifdef TEST6
+int second;    /* IGNORE */
+
+enum tag
+{
+  first,
+  second,      /* ERROR */
+  third
+};
+#endif
+
+#ifdef TEST7
+enum tag
+{
+  first,
+  second,
+  third
+};
+
+enum tag {     /* ERROR */
+  fourth,
+  fifth,
+  sixth
+};
+#endif
+
+#ifdef TEST8
+enum tag x;
+
+enum tag
+{
+  first,
+  second,
+  third
+};
+#endif
diff --git a/support/valdiag/tests/funcdec.c b/support/valdiag/tests/funcdec.c
new file mode 100644 (file)
index 0000000..5af72e4
--- /dev/null
@@ -0,0 +1,48 @@
+
+#ifdef TEST1
+void foo(void);                /* IGNORE */
+int foo(void) { }      /* ERROR */
+#endif
+
+#ifdef TEST2
+void foo(void);                /* IGNORE */
+void foo(int a) {a; }  /* ERROR */
+#endif
+
+
+#ifdef TEST3
+void foo(int);         /* IGNORE */
+void foo(int a, int b) {a;b; } /* ERROR */
+#endif
+
+#ifdef TEST4
+void foo(int, int);    /* IGNORE */
+void foo(int a) {a; }  /* ERROR */
+#endif
+
+#if defined(SDCC) && !(defined(__z80) || defined(__gbz80))
+#define REENTRANT reentrant
+#define HAS_REENTRANT 1
+#else
+#define REENTRANT
+#define HAS_REENTRANT 0
+#endif
+
+#ifdef TEST5
+void foo(int, int) REENTRANT;  /* IGNORE */
+#if HAS_REENTRANT
+void foo(int a, int b) {a; b;} /* ERROR(SDCC && !(__z80 || __gbz80 || SDCC_STACK_AUTO)) */
+#endif
+#endif
+
+#ifdef TEST6
+void foo(int a=1)              /* ERROR */
+{
+}
+#endif
+
+#ifdef TEST7
+void foo(static int a)         /* ERROR */
+{
+}
+#endif
diff --git a/support/valdiag/tests/primtypes.c b/support/valdiag/tests/primtypes.c
new file mode 100644 (file)
index 0000000..1fa00a3
--- /dev/null
@@ -0,0 +1,100 @@
+#ifdef TESTchar
+char a;
+#endif
+
+#ifdef TESTint
+int a;
+#endif
+
+#ifdef TESTlong
+long a;
+#endif
+
+#ifdef TESTshort
+short a;
+#endif
+
+#ifdef TESTintlong
+long int a;
+#endif
+
+#ifdef TESTintshort
+short int a;
+#endif
+
+#ifdef TESTsigned
+signed a;
+#endif
+
+#ifdef TESTunsigned
+unsigned a;
+#endif
+
+#ifdef TESTintsigned
+signed int a;
+#endif
+
+#ifdef TESTintunsigned
+unsigned int a;
+#endif
+
+#ifdef TESTfloat
+float a;
+#endif
+
+#ifdef TESTfloatsigned
+signed float a;                /* ERROR */
+#endif
+
+#ifdef TESTfloatunsigned
+unsigned float a;      /* ERROR */
+#endif
+
+#ifdef TESTfloatshort
+short float a;         /* ERROR */
+#endif
+
+#ifdef TESTfloatlong
+long float a;          /* ERROR */
+#endif
+
+#ifdef TESTdouble
+double a;              /* WARNING(SDCC) */
+#endif
+
+#ifdef TESTdoubleshort
+short double a;                /* ERROR */
+#endif
+
+#ifdef TESTdoublelong
+long double a;         /* WARNING(SDCC) */
+#endif
+
+#ifdef TESTdoublesigned
+signed double a;               /* ERROR */
+#endif
+
+#ifdef TESTdoubleunsigned
+unsigned double a;             /* ERROR */
+#endif
+
+#ifdef TESTbit
+bit a;                 /* ERROR(__z80||__gbz80||__hc08||PORT_HOST) */
+#endif
+
+#ifdef TESTsu1
+signed unsigned int a; /* ERROR */
+#endif
+
+#ifdef TESTsu2
+unsigned signed int a; /* ERROR */
+#endif
+
+#ifdef TESTsu3
+unsigned signed a;     /* ERROR */
+#endif
+
+#ifdef TESTsu4
+signed unsigned a;     /* ERROR */
+#endif
+
diff --git a/support/valdiag/tests/struct.c b/support/valdiag/tests/struct.c
new file mode 100644 (file)
index 0000000..615024d
--- /dev/null
@@ -0,0 +1,76 @@
+
+#ifdef TEST1
+struct tag {
+  int good1;
+  register int bad;    /* ERROR */
+  int good2;
+} badstruct;           /* IGNORE */
+#endif
+
+#ifdef TEST2
+struct tag {
+  int good1;
+  int bad;
+  int bad;     /* ERROR */
+  int good2;
+} badstruct;
+#endif
+
+
+#ifdef TEST3
+struct tag {
+  int good1;
+  int bad:255; /* ERROR */
+  int good2;
+} badstruct;
+#endif
+
+#ifdef TEST4
+struct tag {
+  int good1;
+  int good2;
+} goodstruct1;
+
+struct tag goodstruct2;
+#endif
+
+#ifdef TEST5a
+struct tag {
+  int good1;
+  int good2;
+} goodstruct1;
+
+union tag badunion;    /* ERROR */
+#endif
+
+#ifdef TEST5b
+union tag {
+  int good1;
+  int good2;
+} goodunion1;
+
+struct tag badstruct;  /* ERROR */
+#endif
+
+
+#ifdef TEST6
+struct linklist {
+  struct linklist *prev;
+  struct linklist *next;
+  int x;
+} ll;
+#endif
+
+#ifdef TEST7a
+union tag {
+  struct tag *next;    /* ERROR */
+  int x;
+} ll;
+#endif
+
+#ifdef TEST7b
+struct tag {
+  union tag *next;     /* ERROR */
+  int x;
+} ll;
+#endif
diff --git a/support/valdiag/tests/switch.c b/support/valdiag/tests/switch.c
new file mode 100644 (file)
index 0000000..6a29a9d
--- /dev/null
@@ -0,0 +1,157 @@
+
+char x;
+
+/* Valid switch statement */
+#ifdef TEST1
+char foo(void)
+{
+  switch(x)
+    {
+      char y;
+      
+      case 0:
+        return 0;
+      case 1:
+        return 1;
+      default:
+        y = x+1;
+        return y;
+    }
+}
+#endif
+
+/* Error, duplicate cases */
+#ifdef TEST2
+char foo(void)
+{
+  switch(x)
+    {
+      char y;
+      
+      case 0:          /* IGNORE */
+        return 0;
+      case 1:
+        return 1;
+      case 0:          /* ERROR */
+        return 0;
+      default:
+        y = x;
+        return y;
+    }
+}
+#endif
+
+/* Error, more than one default */
+#ifdef TEST3
+char foo(void)
+{
+  switch(x)
+    {
+      char y;
+      
+      case 0:
+        return 0;
+      case 1:
+        return 1;
+      default:         /* IGNORE */
+        y = x;
+        return y;
+      default:         /* ERROR */
+        return 2;
+    }
+}
+#endif
+
+/* Warn about unreachable code */
+#ifdef TEST4
+char foo(void)
+{
+  switch(x)
+    {
+      char y;
+      x++;             /* WARNING */
+      
+      case 0:
+        return 0;
+      case 1:
+        return 1;
+      default:
+        y = x;
+        return x;
+    }
+}
+#endif
+
+/* Warn about unreachable initializer */
+#ifdef TEST5
+char foo(void)
+{
+  switch(x)
+    {
+      char y=1;                /* WARNING */
+      
+      case 0:
+        return 0;
+      case 1:
+        return 1;
+      default:
+        return y;      /* IGNORE */
+    }
+}
+#endif
+
+/* Error, missing switch */
+#ifdef TEST6
+char foo(void)
+{
+    {
+      case 0:          /* ERROR */
+        return 0;
+      case 1:          /* ERROR */
+        return 1;
+      default:         /* ERROR */
+        return x;
+    }
+}
+#endif
+
+/* Error, switch condition must be integral */
+#ifdef TEST7
+char foo(void)
+{
+  float f;
+  f=x;
+  switch(f)            /* ERROR */
+    {
+      char y;
+      
+      case 0:
+        return 0;
+      case 1:
+        return 1;
+      default:
+        y = x;
+        return x;
+    }
+}
+#endif
+
+/* Error, cases must be integral */
+#ifdef TEST8
+char foo(void)
+{
+  switch(x)
+    {
+      char y;
+      
+      case 0.0:                /* ERROR */
+        return 0;
+      case 1:
+        return 1;
+      default:
+        y = x;
+        return x;
+    }
+}
+#endif
+
diff --git a/support/valdiag/tests/tentdecl.c b/support/valdiag/tests/tentdecl.c
new file mode 100644 (file)
index 0000000..90bc17f
--- /dev/null
@@ -0,0 +1,119 @@
+
+#ifdef TEST0
+int a;
+int a;
+#endif
+
+#ifdef TEST1
+int a;         /* IGNORE */
+char a;                /* ERROR */
+#endif
+
+#ifdef TEST2
+int a;         /* IGNORE */
+int *a;                /* ERROR */
+#endif
+
+#ifdef TEST3
+int *a;                /* IGNORE */
+int a[5];       /* ERROR */
+#endif
+
+/* array size must match */
+
+#ifdef TEST4
+int a[4];      /* IGNORE */
+int a[5];      /* ERROR */
+#endif
+
+/* but it is legal to clarify */
+/* an incomplete type */
+
+#ifdef TEST4b
+int a[];
+int a[5];
+#endif
+
+/* type qualifier must match */
+
+#ifdef TEST5
+int a;         /* IGNORE */
+volatile int a; /* ERROR */
+#endif
+
+#ifdef TEST6
+int a;         /* IGNORE */
+const int a;   /* ERROR */
+#endif
+
+#ifdef TEST7
+int a=1;       /* IGNORE */
+int a=2;        /* ERROR */
+#endif
+
+#ifdef TEST7a
+int a=1;
+int a;
+#endif
+
+#ifdef TEST8
+int a=1;       /* IGNORE */
+int a=1;       /* ERROR */
+#endif
+
+#if defined(__z80) || defined(__gbz80)
+#define XDATA
+#define DATA
+#else
+#define XDATA xdata
+#define DATA data
+#endif
+
+#ifdef TEST9
+#ifdef SDCC
+XDATA int a;
+DATA int a;    /* ERROR(SDCC && !(__z80 || __gbz80)) */
+#endif
+#endif
+
+#ifdef TEST9b
+#ifdef SDCC
+DATA int a;
+XDATA int a;   /* ERROR(SDCC && !(__z80 || __gbz80)) */
+#endif
+#endif
+
+#ifdef TEST9c
+#ifdef SDCC
+extern DATA int a;
+DATA int a;
+#endif
+#endif
+
+#ifdef TEST9d
+#ifdef SDCC
+extern XDATA int a;
+XDATA int a;
+#endif
+#endif
+
+#ifdef TEST9e
+#ifdef SDCC
+extern XDATA int a;
+DATA int a;    /* ERROR(SDCC && !(__z80 || __gbz80)) */
+#endif
+#endif
+
+#ifdef TEST9f
+#ifdef SDCC
+extern DATA int a;
+XDATA int a;   /* ERROR(SDCC && !(__z80 || __gbz80)) */
+#endif
+#endif
+
+#ifdef TEST10
+#if defined(SDCC) && !(defined(__z80) || defined(__gbz80))
+extern volatile XDATA at 0 int a;
+volatile XDATA int a;  /* ERROR(SDCC && !(__z80 || __gbz80)) */
+#endif
+#endif
diff --git a/support/valdiag/tests/typedef.c b/support/valdiag/tests/typedef.c
new file mode 100644 (file)
index 0000000..a3c8422
--- /dev/null
@@ -0,0 +1,43 @@
+
+#ifdef TEST1
+typedef union {
+  long l;
+  float f;
+} floatlong;
+
+char func(char floatlong)
+{
+  return floatlong;
+}
+#endif
+
+#ifdef TEST2
+typedef union {
+  long l;
+  float f;
+} floatlong;
+
+long func(float x)
+{
+  typedef union {
+    float f2;
+    long l2;
+    char c[4];
+  } floatlong;
+  floatlong fl;
+  
+  fl.f2=x;
+  return fl.l2;
+}
+#endif
+
+#ifdef TEST3
+typedef int I;         /* IGNORE */
+typedef int I;         /* ERROR */
+#endif
+
+#ifdef TEST4
+typedef int I;         /* IGNORE */
+typedef char I;                /* ERROR */
+#endif
+
diff --git a/support/valdiag/valdiag.py b/support/valdiag/valdiag.py
new file mode 100644 (file)
index 0000000..2a4ed75
--- /dev/null
@@ -0,0 +1,304 @@
+#!/usr/bin/env python
+#---------------------------------------------------------------------------
+#  valdiag.py - Validate diagnostic messages from SDCC/GCC
+#        Written By -  Erik Petrich . epetrich@users.sourceforge.net (2003)
+#
+#   This program is free software; you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation; either version 2, or (at your option) any
+#   later version.
+#   
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#   
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#   
+#   In other words, you are welcome to use, share and improve this program.
+#   You are forbidden to forbid anyone else to use, share and improve
+#   what you give them.   Help stamp out software-hoarding!  
+#---------------------------------------------------------------------------
+
+import sys, string, os, popen2, re
+
+macrodefs = {}
+
+gcc = {
+    "CC":"gcc",
+    "CCFLAGS":"-c -Wall",
+    "CCDEF":"-D",
+    "CCOUTPUT":"-o",
+    "defined": {
+        "__GNUC__":"1"
+    },
+    "ignoremsg": [
+    ]
+}
+
+sdcc = {
+    "CC":"../../bin/sdcc",
+    "CCFLAGS":"-c -m{port}",
+    "CCDEF":"-D",
+    "CCOUTPUT":"-o",
+    "defined": {
+        "SDCC":"1",
+        "SDCC_{port}":"1",
+        "__{port}":"1"
+    },
+    "ignoremsg": [
+        "code not generated.*due to previous errors",
+        "unreferenced function argument"
+    ]
+}
+
+testmodes = {
+    "host":{
+        "compiler":gcc,
+        "port":"host",
+        "defined": {
+            "PORT_HOST":"1"
+        }
+    },
+    "mcs51":{
+        "compiler":sdcc,
+        "port":"mcs51"
+    },
+    "mcs51-large":{
+        "compiler":sdcc,
+        "port":"mcs51",
+        "flags":"--model-large",
+        "defined": {
+            "SDCC_MODEL_LARGE":"1"
+        }
+    },
+    "mcs51-stack-auto":{
+        "compiler":sdcc,
+        "port":"mcs51",
+        "flags":"--stack-auto",
+        "defined": {
+            "SDCC_STACK_AUTO":"1"
+        }
+    },
+    "ds390":{
+        "compiler":sdcc,
+        "port":"ds390"
+    },
+    "z80":{
+        "compiler":sdcc,
+        "port":"z80"
+    },
+    "gbz80":{
+        "compiler":sdcc,
+        "port":"gbz80"
+    },
+    "hc08":{
+        "compiler":sdcc,
+        "port":"hc08"
+    },
+    "pic14":{
+        "compiler":sdcc,
+        "port":"pic14"
+    },
+    "pic16":{
+        "compiler":sdcc,
+        "port":"pic16"
+    }
+}
+    
+
+def evalQualifier(expr):
+    global macrodefs
+    tokens = re.split("([^0-9A-Za-z_])", expr)
+    for tokenindex in range(len(tokens)):
+        token = tokens[tokenindex]
+        if token in macrodefs:
+            tokens[tokenindex] = macrodefs[token]
+        elif token == "defined":
+            tokens[tokenindex] = ""
+            if tokens[tokenindex+2] in macrodefs:
+                tokens[tokenindex+2] = "1"
+            else:
+                tokens[tokenindex+2] = "0"
+        elif len(token)>0:
+            if token[0]=="_" or token[0] in string.ascii_letters:
+                tokens[tokenindex] = "0"
+    expr = string.join(tokens,"")
+    expr = string.replace(expr,"&&"," and ");
+    expr = string.replace(expr,"||"," or ");
+    expr = string.replace(expr,"!"," not ");
+    return eval(expr)
+    
+def expandPyExpr(expr):
+    tokens = re.split("({|})", expr)
+    for tokenindex in range(1,len(tokens)):
+        if tokens[tokenindex-1]=="{":
+            tokens[tokenindex]=eval(tokens[tokenindex])
+            tokens[tokenindex-1]=""
+            tokens[tokenindex+1]=""
+    expandedExpr = string.join(tokens,"")
+    return expandedExpr
+    
+def addDefines(deflist):
+    for define in deflist.keys():
+        expandeddef = expandPyExpr(define)
+        macrodefs[expandeddef] = expandPyExpr(deflist[define])
+
+def parseInputfile(inputfilename):
+    inputfile = open(inputfilename, "r")
+    testcases = {}
+    testname = ""
+    linenumber = 1
+    
+    # Find the test cases and tests in this file
+    for line in inputfile.readlines():
+        
+        # See if a new testcase is being defined
+        p = string.find(line, "TEST")
+        if p>=0:
+            testname = string.split(line[p:])[0]
+            if not testcases.has_key(testname):
+                testcases[testname] = {}
+        
+        # See if a new test is being defined
+        for testtype in ["ERROR", "WARNING", "IGNORE"]:
+            p = string.find(line, testtype);
+            if p>=0:
+                # Found a test definition
+                qualifier = string.strip(line[p+len(testtype):])
+                p = string.find(qualifier, "*/")
+                if p>=0:
+                    qualifier = string.strip(qualifier[:p])
+                if len(qualifier)==0:
+                    qualifier="1"
+                qualifier = evalQualifier(qualifier)
+                if qualifier:
+                    if not linenumber in testcases[testname]:
+                        testcases[testname][linenumber]=[]
+                    testcases[testname][linenumber].append(testtype)
+        
+        linenumber = linenumber + 1
+    
+    inputfile.close()
+    return testcases
+
+def parseResults(output):
+    results = {}
+    for line in output:
+        print line,
+        
+        if string.count(line, "SIGSEG"):
+            results[0] = ["FAULT", string.strip(line)]
+            continue
+        
+        # look for something of the form:
+        #   filename:line:message
+        msg = string.split(line,":",2)
+        if len(msg)<3: continue
+        if msg[0]!=inputfilename: continue
+        if len(msg[1])==0: continue
+        if not msg[1][0] in string.digits: continue
+        
+        # it's in the right form; parse it
+        linenumber = int(msg[1])
+        msgtype = "UNKNOWN"
+        uppermsg = string.upper(msg[2])
+        if string.count(uppermsg,"ERROR"):
+            msgtype = "ERROR"
+        if string.count(uppermsg,"WARNING"):
+            msgtype = "WARNING"
+       msgtext = string.strip(msg[2])
+        ignore = 0
+       for ignoreExpr in ignoreExprList:
+           if re.search(ignoreExpr,msgtext)!=None:
+               ignore = 1
+        if not ignore:
+            results[linenumber]=[msgtype,string.strip(msg[2])]
+    return results
+
+def showUsage():
+    print "Usage: test testmode cfile [objectfile]"
+    print "Choices for testmode are:"
+    for testmodename in testmodes.keys():
+        print "   %s" % testmodename
+    sys.exit(1)
+      
+# Start here         
+if len(sys.argv)<3:
+    showUsage()
+    
+testmodename = sys.argv[1]
+if not testmodename in testmodes:
+    print "Unknown test mode '%s'" % testmodename
+    showUsage()
+
+testmode = testmodes[testmodename]
+compilermode = testmode["compiler"]
+port = expandPyExpr(testmode["port"])
+cc = expandPyExpr(compilermode["CC"])
+ccflags = expandPyExpr(compilermode["CCFLAGS"])
+if "flags" in testmode:
+    ccflags = string.join([ccflags,expandPyExpr(testmode["flags"])])
+if len(sys.argv)>=4:
+    if "CCOUTPUT" in compilermode:
+        ccflags = string.join([ccflags,expandPyExpr(compilermode["CCOUTPUT"]),sys.argv[3]])
+if "defined" in compilermode:
+    addDefines(compilermode["defined"])
+if "defined" in testmode:
+    addDefines(testmode["defined"])
+if "ignoremsg" in compilermode:
+    ignoreExprList = compilermode["ignoremsg"]
+else:
+    ignoreExprList = []
+
+inputfilename = sys.argv[2]
+try:
+    testcases = parseInputfile(inputfilename)
+except IOError:
+    print "Unable to read file '%s'" % inputfilename
+    sys.exit(1)
+
+casecount = len(testcases.keys())
+testcount = 0
+failurecount = 0
+
+for testname in testcases.keys():
+    ccdef = compilermode["CCDEF"]+testname
+    cmd = string.join([cc,ccflags,ccdef,inputfilename])
+    print
+    print cmd
+    spawn = popen2.Popen4(cmd)
+    spawn.wait()
+    output = spawn.fromchild.readlines()
+    
+    results = parseResults(output)
+    
+    if len(testcases[testname])==0:
+        testcount = testcount + 1 #implicit test for no errors
+
+    # Go through the tests of this case and make sure
+    # the compiler gave a diagnostic
+    for checkline in testcases[testname].keys():
+        testcount = testcount + 1
+        if checkline in results:
+            if "IGNORE" in testcases[testname][checkline]:
+                testcount = testcount - 1  #this isn't really a test
+            del results[checkline]
+        else:
+            for wanted in testcases[testname][checkline]:
+                if not wanted=="IGNORE":
+                    print "--- FAIL: expected %s" % wanted,
+                    print "at %s:%d" % (inputfilename, checkline)
+                    failurecount = failurecount + 1
+
+    # Output any unexpected diagnostics    
+    for checkline in results.keys():
+        print '--- FAIL: unexpected message "%s" ' % results[checkline][1],
+        print "at %s:%d" % (inputfilename, checkline)
+        failurecount = failurecount + 1
+
+print
+print "--- Summary: %d/%d/%d: " % (failurecount, testcount, casecount),
+print "%d failed of %d tests in %d cases." % (failurecount, testcount, casecount)