display | more...

A lot of interpreted languages come with interactive interpreters, or interactive consoles, or whatever you like to call them. What that is, is a program that lets you type code in and see the result immediately. LISP people love this stuff, but they're hardly the only ones. If you ever had an Apple II back in the day, you'll remember that its shell was an interactive interpreter for a gruesome form of line-number-bearing BASIC (which was still considerably more powerful and elegant than the native shell language that ships with Windows XP today). In effect, what you get is a fiendishly powerful calculator program.

At runtime, any interactive interpreter follows the same three steps: It reads input from the user, it evaluates it, and it prints the result: Read-eval-print, over and over, in a loop.

Any language which has an eval() function can be used to write a quick'n'dirty interactive interpreter for itself. If the language will carry state over from one eval() call to the next ("state" meaning variables and such), you'll get something that's actually useful. If you were serious about the thing, you'd like to be able to reflect that state, dump it in a file on exit, and reload it during a later session if the urge struck. If you did that, you'd be turning it into a real program. The fun thing about doing this is that -- language permitting -- the program's own namespace is open to the code the user is executing. The line between code and data blurs, and you can do weird stuff. I don't know if it's necessarily useful, but "weird" should be enough for anybody1.

You can do this in an HTML page with JavaScript, if you've got half an hour to kill: You put an input box and an output box in a form, and instead of a loop, you do your eval and "print" in the form's onsubmit handler (and remember to return false so the page doesn't reload and discard whatever just happened).

Let's do an example. Our favorite Weird Little Language this week is Ruby2, but nobody speaks a word of it, so we'll use Perl instead. (<> means "read a line from standard input"; $_ means "the last line read from standard input").


    print( "Ctrl+C to exit.\n> " );
    while ( <> ) {
        print( eval( $_ ) . "\n> " );

When you run it, it looks like this:

    $ ./rep
    > sub foo() { print( "bar" ); }

    > foo
    > $a = 45
    > $a * 123
    > exit

Notice that when we call foo(), it prints the return value (1) after executing the function. That's clumsy, but what do you want from a four-line program?

1 eval() functions are useful in a lot of entertaining ways: Everything 2, for example, runs on the Everything Engine. That Engine is a Perl program which generates HTML pages based on records stored in a database. Much of the actual page generation is done by calling eval() to evalulate other Perl code which is stored in the same database as everything else. Now, that is useful. I think...

2 Here it is, in case anybody cares. The exception handling ("rescue") is because Ruby is finickier than Perl about errors. We have to choose a context for eval() to happen in if we want anything to persist, but that's more of a feature than a bug, if you ask me: You can have more than one of them. The each thing is what Ruby calls an "iterator", and by chance, I think we just might have a writeup there that covers that very thing...

    # Create a context for state to persist in between eval() calls
    context = binding();

    print( "\"exit\" to exit.\n> " );
    $stdin.each { |line|
            puts( eval( line, context ) );
        rescue SyntaxError, NameError => err
            puts( err );

        print( "> " );

Log in or register to write something here or to contact authors.