Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Some of these are not so much "human centered" issues as not cutting corners in the compiler front end.

Many years ago I wrote the front end of a compiler-like system (it was for formal specifications, not for runnable code) and dealt with some of these problems. Whenever a type problem was detected, the error was reported and the type of the failed object was changed to an internal error type. For any error in which an error type was involved, no message was generated. This avoided error cascading, something GCC inflicted on its users for decades.

For parse errors, display the line in error and mark correctly the item involved in the error. Don't just display the index into the source stream at the point the error was detected; that's often a token or two beyond the problem. Work back to the point at which things stopped making sense to the parser. You have to carry source position info with each token, but it's worth it.

For errors which represent an inconsistency between several parts of the source code, show all the places that conflict, not just one side of the conflict. Rust is good about this. They have to be, because the borrow checker reports inconsistencies between different code sections, not just declarations and uses.



It also helps if your syntax supports error recovery. For example, if 'if' statements end with 'fi', 'do' statements end with 'od', and function definitions statements end with 'end', and you get 'if ... do ... fi', you can report that you are missing a 'od' in the program, and recover parsing after the 'fi'.

C is horrible in this respect; all nesting looks the same. Because of that it took clang lots of effort to get good error recovery, for example to correctly report a missing semicolon at the end of a header file instead of reporting an error in the file including it (http://blog.llvm.org/2010/04/amazing-feats-of-clang-error-re... (NB: that page is 5 years old, and does not represent the current state of gcc))

gcc makes that job even harder by allowing nested function definitions. That means that accidentally forgetting a single '}', as in

   void f( int i) {
     if( i > 2) {
       exit(EXIT_FAILURE);
   }
   void g() {}
   [...]
   void h() {}
will make the compiler think that g() and h() are nested function definitions. So, the error you get is a “missing closing brace" on the last line of your file. Without nested function support, the error would be reported on the 'void g() {}' line. Still incorrect, but potentially thousands of lines closer to the source.

The Algol compiler (helped by Algol's syntax) I used years ago was way better. It frequently gave errors of the form

  "x undeclared. Assumed real"
(if, say, you call sin(x) without declaring x) or

  "semicolon missing after 'end' (inserted)”
Compilation would still fail after such errors, but you often would get meaningful error messages for the entire program. That was quite a boon if the compilation is run in batch, but it still is a good idea nowadays.


Another option is to make indentation meaningful to fix C's problem here.


You could use the indentation as a hint for error reporting even without giving it syntactic meaning.


Good and workable compromise! Perhaps even make it a proper warning, even if inconsistent indentation is the only thing wrong.


if you follow a sane style guide, it'll be obvious where thid error is anyway from the first error line no. usually and it won't matter that you got garbage errors.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: