Error recovery (long)

John Sambrook john at uw-nsr.UUCP
Thu May 29 16:00:41 AEST 1986


[]

Regarding error recovery in C compilers, I like the error recovery
provided by the Data General C compiler.  Here is an example of a 
botched program:

	main() {
		int	a = 0	/* missing ";" */

		printf("a: %s\n",  (a == 1) ? "1" : "?"; /* missing ")" */
	}

When compiled the following is written on stderr:

	Error 502 severity 2 beginning on line 4 (Line 4 of file main.c) 
		printf("a: %s\n",  (a == 1) ? "1" : "?";
		^
	Syntax Error.
	A symbol of type ";" has been inserted before this symbol.
	 
	 
	Error 502 severity 2 beginning on line 4 (Line 4 of file main.c) 
		printf("a: %s\n",  (a == 1) ? "1" : "?";
		                                       ^
	Syntax Error.
	A symbol of type ")" has been inserted before this symbol.

In this example the compiler produced a program that executed correctly.

To be fair, both errors are "errors of omission."  I believe, but do not
assert, that these errors are easier to repair than other types of errors.
In the event of serious errors the compiler will cease code generation and
only check the remaining input.  I don't know the parsing method used in
this compiler; it does not seem to suffer from poor error recovery as do 
many recursive-descent parsers.

While on the subject of compilers, I would like to share two other features
of this compiler that I find useful.  I have not found these features in
other C compilers that I have used, although I have heard that the VAX/VMS
C compiler is very good.

The first feature is the ability to generate a stack trace ("traceback") 
in the event of a serious error.  There are two compiler switches that
control the amount of information in a traceback.  The "-Clineid" switch
causes the offending line number to be included while the "-Cprocid" switch 
causes the procedure name to be included.

The second feature is the ability to declare certain data structures as
"read only." This is done via a compiler switch "-R" and applies to all 
data structures that are initialized to a constant value within the 
compilation unit.

Here is an example program that demonstrates both features:

	int a = 1;					/* "read only" */

	main() {
	    	int	b;				/* "read / write" */

		/* this is legal */
		b = a;

		/* prove it */
		printf("a: %d  b: %d\n", a, b);

		/* this is not */
		a = 2;

		/* lie detector */
		printf("Can't happen\n");
	}

This program was compiled with "cc -R -Clineid -Cprocid main.c -o main."
Executing the program produced the following output on stderr:

	a: 1  b: 1
	
	ERROR         71237.
	from line 13 of main.
	
	Call Traceback:
	
	from fp=16000002722,  pc=16001754200,   line 10 of main
	from fp=          0,  pc=16001762472
	
	Hardware protection violation: Write access denied.

In the traceback the phrase "line 10" is because "-Clineid" was 
specified at compile time.  The phrase "of main" is because "-Cprocid" 
was specified at compile time.  Note though that the two "offending"
line numbers differ.  I suspect that this is because the last line to
execute successfully was at line 10; line 13 did not execute successfully
but rather generated a processor trap.

Some people might say that this compiler is too verbose, or that the
features cost too much in terms of execution overhead.  I have not found
this to be the case.  And, while I hate to see any tracebacks, I find
them to be far better than:

	% mumble foo bar
	Segmentation violation - core dumped.
	%

Please note that I do not intend to participate in any "holy wars."
I do not speak for Data General nor do I receive any compensation 
from them.  I just felt that this might be of interest to the readers
of this group.

-- 
John Sambrook				Work: (206) 545-2018
University of Washington WD-12		Home: (206) 487-0180
Seattle, Washington  98195		UUCP: uw-beaver!uw-nsr!john



More information about the Comp.lang.c mailing list