LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-12-2011, 10:29 AM   #1
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443
Blog Entries: 3

Rep: Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723
A few questions about implementing exceptions in my interpreter


The first is that if the exception is not handled, it should be printed to stderr, and that includes the exception's name. The problem is that in my language, nothing has a fixed, global name, including classes and functions. The only way you can give them a "name" is by putting them in variables.

The second, which also has to do with printing an unhandled exception, is how do I get line, column, and filename info? Once the code is converted to an AST, it has no concept of filenames, lines, or columns.

The third, and the last one that has to do with printing an unhandled exception, is how do I get a backtrace?

Finally, there are some exceptions that are thrown by the interpreter itself (caused by doing things like reading non-existent variables or importing a file that's not there). Do the exceptions these throw have to be in the global scope all the time? Having to initialize variables in the global scope instead of leaving it empty seems like extra trouble. I solved this with the builtin types (like integers and strings) by creating keywords that evaluate to the types.
 
Old 05-12-2011, 10:49 AM   #2
SigTerm
Member
 
Registered: Dec 2009
Distribution: Slackware 12.2
Posts: 379

Rep: Reputation: 234Reputation: 234Reputation: 234
Quote:
Originally Posted by MTK358 View Post
The first is that if the exception is not handled, it should be printed to stderr, and that includes the exception's name. The problem is that in my language, nothing has a fixed, global name, including classes and functions. The only way you can give them a "name" is by putting them in variables.
This is incorrect, you can use typeid with C++ exception classes. Derive your own class from std::exception, catch it, and use typeid().name() to get exception class. Just make sure you catch it by reference (catch std::exception& e), not by value. Also std::exception has very handy what() method for passing error messages.
Code:
void reportException(const std::exception& e){
	QString errMsg = QString(QObject::tr("exception caught:\nclass: %1\nmessage: %2")).arg(typeid(e).name()).arg(QString::fromUtf8(e.what()));
	qCritical() << errMsg;
}

....
	catch(std::exception& e){
		reportException(e);
	}
Quote:
Originally Posted by MTK358 View Post
The second, which also has to do with printing an unhandled exception, is how do I get line, column, and filename info? Once the code is converted to an AST, it has no concept of filenames, lines, or columns.
There are more or less standard built-in macros(es?)
Code:
__FILE__
__FUNCTION__
__LINE__
that are supported by g++/msvc compilers. Use them when you throw exception.

Quote:
Originally Posted by MTK358 View Post
The third, and the last one that has to do with printing an unhandled exception, is how do I get a backtrace?
That's platform-dependent, and you should REALLY google for tutorials - in last 10 years somebody most likely wrote at least one linux backtrace tutorial. I wouldn't bother. Unless it is a segfault, backtrace is not necesarry, and if it IS a segfault, then you'll simply need to make coredump and examine it later within debugger.

Quote:
Originally Posted by MTK358 View Post
Do the exceptions these throw have to be in the global scope all the time?
Sentence doesn't make much sense. Anyway, that's up to you to decide - the answer would require analysis of your interpreter. The easiest way is to handle interpreter exceptions would be to introduce additional exception class (derived from std::exception) for interpreter exceptions, and try to catch it before catching std::exception - simply use several catch blocks.

Last edited by SigTerm; 05-12-2011 at 10:54 AM.
 
Old 05-12-2011, 11:00 AM   #3
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443

Original Poster
Blog Entries: 3

Rep: Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723
You seem to have completely misunderstood my question.

I'm not talking about C++, but about my interpreted language.

I asked how to get a backtrace of the interpreted program, not the C++ interpreter. I also asked how to get the line and column info of the spot in the interpreted program where the exception was thrown, not what line and column a C++ exception was thrown at.
 
0 members found this post helpful.
Old 05-12-2011, 11:11 AM   #4
SigTerm
Member
 
Registered: Dec 2009
Distribution: Slackware 12.2
Posts: 379

Rep: Reputation: 234Reputation: 234Reputation: 234
Quote:
Originally Posted by MTK358 View Post
I asked how to get a backtrace of the interpreted program, not the C++ interpreter.
Well, in this case I don't really see the problem.
Your interpreter most likely has a "stack" or similar structure that stores return addresses. Get a copy of "stack" when exception is thrown, walk through the structure, and you'll get a backtrace.

Quote:
Originally Posted by MTK358 View Post
I also asked how to get the line and column info of the spot in the interpreted program where the exception was thrown, not what line and column a C++ exception was thrown at.
You won't be able to get column unless you're talking about syntax errors - exeption gets thrown by statement, not by character. To get line information, you obviously will have to store it within interpreter - line number for every statement. 2..4 extra bytes per statement will do the trick. You're the author, so you can add information you need. If you think it takes too much space, then you could try searching for a way to compress it.

As I already said, more detailed answer would require complete analysis of your interpreter which is beyond the scope of this forum.
 
Old 05-12-2011, 12:15 PM   #5
MTK358
LQ 5k Club
 
Registered: Sep 2009
Posts: 6,443

Original Poster
Blog Entries: 3

Rep: Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723Reputation: 723
Quote:
Originally Posted by SigTerm View Post
Well, in this case I don't really see the problem.
Your interpreter most likely has a "stack" or similar structure that stores return addresses. Get a copy of "stack" when exception is thrown, walk through the structure, and you'll get a backtrace.
Actually, it currently just uses a set of recursive AST-walking functions, not any kind of VM (but I am interested in how to do a bytecode VM. The problem is that when I try to desrch about it, almost all the results are about JVM).

Quote:
Originally Posted by SigTerm View Post
You won't be able to get column unless you're talking about syntax errors - exeption gets thrown by statement, not by character. To get line information, you obviously will have to store it within interpreter - line number for every statement. 2..4 extra bytes per statement will do the trick. You're the author, so you can add information you need. If you think it takes too much space, then you could try searching for a way to compress it.

As I already said, more detailed answer would require complete analysis of your interpreter which is beyond the scope of this forum.
I considered putting line/column info into each AST node, but it doesn't seem worth it. I'll just leave that alone for now.

Last edited by MTK358; 05-12-2011 at 12:19 PM.
 
Old 05-12-2011, 05:50 PM   #6
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,642
Blog Entries: 4

Rep: Reputation: 3933Reputation: 3933Reputation: 3933Reputation: 3933Reputation: 3933Reputation: 3933Reputation: 3933Reputation: 3933Reputation: 3933Reputation: 3933Reputation: 3933
Long ago, I did it this way ...

Line-numbers are simply stored as a field in the bytecode record! Yup, every bytecode has the line-number it came from. (I mean, do I really care about 4 extra bytes per instruction?)

(In the same vein, feel free to put line/column numbers and whatever else you'd like to keep good 'n handy, into an AST node! We are not still in the days when we had to split compilers into "core-loads" and carefully record them onto magnetic drums...)

The interpreter maintains an exception-handler stack. (This, like all other such stacks, is not "in program-visible 'memory,'" but is a separate data-structure.) When an exception occurs, the topmost entry is the active handler. (If an exception is occurring within an exception handler, the stack is popped until we find a handler that we can use.)

Just to clarify ... the p-code execution routine within the interpreter is wrapped in a try..except block. If an exception occurs while executing an instruction, we wind up here. At this point the interpreter captures the error-information and puts itself into an EXCEPTION_OCCURRED state. From the point-of-view of the implementation language, "the exception is over now." The interpreter now searches its stack in order to figure out what the user program wants to do with the exception.

If there is no usable stack-entry, the user program either didn't prepare to handle exceptions or the exception occurred within its outermost exception-handling routine. (Either way, "You're dead, Jim...") The interpreter puts itself into an ERROR_STOP state and returns to its caller.

Since my language implements "try..finally," there's one more twist of weirdness .. an opcode called DO_FINALLY. While compiling exception-handling statements we remember how many nested "try..finally" blocks we're in, and we generate that many copies of this instruction before, say, "return." This opcode looks for a "finally" handler that hasn't been tripped yet, pops the stack until it gets there, then sends us off into that code. The finally-block ends with an END_FINALLY instruction, which sends us back to the instruction following DO_FINALLY. (When either of these instructions are executing, we know that "at the moment, everything is okay... nothing, ahh, exceptional is happening.")

It seems to work well enough, although once I saw it misbehave most oddly. That interpreter's been in service now for about fifteen years...

Last edited by sundialsvcs; 05-12-2011 at 06:01 PM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
A few questions about making an interpreter MTK358 Programming 3 01-21-2011 03:45 PM
How to Writing exceptions cklckl48 Linux - Kernel 6 09-22-2010 12:47 AM
Couple questions about implementing shell commands rohando Programming 2 06-29-2008 03:35 PM
Exceptions bianchi Programming 1 11-17-2005 08:36 PM
Regarding Exceptions eshwar_ind Programming 1 05-03-2005 12:23 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:18 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration