|Name:||Listener class library|
|Author:||David Pacheco (email@example.com)|
The Listener class is intended to encapsulate the functionality of a read-eval- print loop used, for example, in command-line shells, console interpreters, etc.
After instantiating an object of type
Listener, you can call the
startLoop() member function to begin the loop. It will first prompt
the user for input. The input is passed to a handler, and the result of that
handler is output back to the user.
The important thing is that the input is safely entered. All quotation marks
(both " and ') must be properly closed. If not, the prompt will continue.
StatusChecker object (similar to the
one) is used to see if the input is complete. If not, the user is prompted again
to complete the entry.
make. This will create the
libListener.afile, which you can then link in another
Listener.hheader file in any C++ source file you compile that uses the Listener class. Also be sure to link the library you
make clean. To get rid of all files created by compiling this source, do
For sample source code, see the
test.cpp source file included
in this archive. To compile this, run
make test. It shouldn't be
hard to figure out, but I'm going to explain the class anyway.
The only parts of the class the client directly needs to interact with are
the constructor and the
startLoop() function (although you can
directly use the
to create your own REP loop). You can also use the static
predicate in your derived
StatusChecker classes (see below) to
see if a string is "closed" with respect to some char (like quotation
marks, though that particular one is handled automatically) or a pair (like
startLoop()is self-explanatory and takes no parameters.
getStatement()prompts the user and returns their input.
putResult(string result)prints the result, including a newline if it printed anything.
The constructor, then, is the most complicated part. It takes several parameters, some optional (defaults listed in [square brackets]):
Handler: see below
StatusChecker: see below
string prompt: the text to display BEFORE the prompt
char promptChar[>]: the actual promptChar (see below)
istream input[std::cin]: where the Listener gets its input
Let's take these one-by-one.
The Handler is simply a class (inherited from the ADT* Handler provided in the Listener.h header file) which provides a functional action() method. You must specify this; there is no default. The action() method is called on every complete user input with a string parameter representing the input. It returns a string that will be displayed to the user (the result of the print).
In the example of using the Listener as an interactive interpreter, action() will be passed a statement to be evaluated, evaluate it, and return a string representing the result. This is why there cannot be a default - it's the primary means by which the Listener is customized.
The StatusChecker, like the Handler, is a class inherited from the ADT StatusChecker provided in the Listener.h header file. Although there could be a defult, there currently isn't one. If you really want a do-nothing StatusChecker, you have to write it yourself.
The point of the StatusChecker is to provide further checking on the input, so that if it's incomplete, the user can be prompted to finish it. For example, Scheme inputs must have balanced parentheses. Thus, in the test.cpp, where a StatusChecker for Scheme inputs is defined, it simply checks that the number of open paren's matches the number of closed ones. You can customize this to your own needs (e.g. you could write one for SQL queries that simply makes sure that the query ends with a semicolon).
The prompt string is displayed at the beginning of the loop, followed by the prompt character. If the input is incomplete, the prompt continues using the prompt character only. If the input has unmatching quoted characters, they are included in the prompt. A sample Scheme exchange, where the prompt has value "scheme" and the promptChar is ">":
scheme> (define foo "string "> " > )
On the second line, the user finished the quoted string (having been prompted to do so), and on the third, s/he finished the statement.
The last part of the constructor is the input stream, which defaults to std::cin. Originally (as you can tell by looking at the source files) both the input and output were customizable, but I changed the implementation to use GNU's readline instead of the standard getline(). readline() deals directly with stdout, and I didn't have the need to customize that functionality. This part of the constructor may be taken out in the future, because there's little reason to change the input stream, and even less so if you can't change the output stream as well.
1.0: First release. Fully functional.
*ADT = abstract data type
Back to Projects
Back to Phoenix Web Home.
Last updated 2003-01-21