merging the new code into master

After 3~4 days of coding, I’ve just merged the parserlexer branch back into master; I love coding 🙂

 commit 9857e5e9556f31543075fb4a74350dbda97a42e5
Merge: c9a8ae4... bb425eb...
Author: Terry ....snip...
Date: Wed Apr 8 07:23:19 2009 +0000

Merge branch 'parserlexer'

The new parser, lexer, and quote expansion code (+ a few bugfixes) has
finally been merged into the mainline of development (branch 'master').
This marks the new sh_eval(), tpsh_parse(), expand_quotes, tpsh_lex()
functions in such a way that they should be considered 'stable' for
general usage.

some nice things that come with this:

a sane way of quoting stuff; but not sh compatible (”’ = ‘, not an error), more then one set of quotes on the line; and things like `cd /foo; vi bar` finally work xD. In the course of the necessary bug smashin’ for the merge, I’ve also cleaned out a few pains in the todo file, that have been there since last month++ lol.

things that remain to be done: pluggable completion; make completion play nicer with perl/gnu readline backends; restore support for pipes (critical); handling of keybinding (likely painful across perl/gnu/zoid Term::ReadLine backends; but at least zoid is nice…). In the more long term: control flow, (subshells), better `handling`, {anonymous macro/grouping}, more advanced I/O redirections (i.e. only >, >>, and < currently work lol); making `fc -l` and `history list` use a format for display rather then print(); make &do_getopt able to be configured by callers (so fc can accept negative indexes, etc); give a way to turn off shell options (set - and set + currently turn on, only lol); and who knows what else that I can't remember atm.
and to abuse {erls idea of objects and verbs: eval { $spidey sleep $now };

I wonder if a programmer goes to heaven, does GOD let him study HIS assembly language?

tpsh: test of expand_quotes()

$ echo 'hi bye' foo "$USER" and "~" or ~
expand_quotes ': echo | hi bye | foo "$USER" and "~" or ~
expand_quotes ": foo | $USER | and "~" or ~
expand_quotes ": and | ~ | or ~
hi bye foo $USER and ~ or /usr/home/Terry
$

# note:
# the 2 spaces /displayed/ between hi and bye are a bug in
# tpsh; echo'ing things to file via I/O redirection works
# properly. "$USER" is not expanded because expand_parameters()
# still needs adjustments.
#

tpsh_parse invokes expand_quotes() to break up its input line based on the shells quoting rules; and proceeds to go about it’s business. tpsh_lex() then accepts the token buffer and begins building a new data structure from it. The tokens from tpsh_parse get analyzed and reassembled “on the quotes”, i.e. it will do it’s check on ‘hi ‘ and ‘bye’ and the rest as separate elements; then reassemble the argument vectors as an array reference: becoming ‘hi bye’ again. (id est quote expansions add escapes to tell the lex phase where to rejoin things) After everything is said and done between parse and lex, the queue like data structure is ready, the argument vectors contained there in are ready to be mapped onto resolve_cmd() calls for execution.

To hunt down any other booboos in the expand_quotes() subroutine, I’ve made it display it’s work, so I can see how it detects what when testing the shell. basically as “expand_quotes QUOTE: unquoted | quoted | remainder”.

As one can guess from what the above shell snippet implies: quoting is handled recursively. Because I’m used to languages with finite stack space and no reliable tail call optimizations; I almost never write recursive functions of any kind, whether they are tco’able or not. Algorithmically, expand_quotes() is a very simple procedure.

It expects to be called with an input line; and treats multiple arguments accordingly (for now). Internally a dispatch table and token stack are maintained; the table contains references to anonymous subroutines, to which the scanned elements are delegated to for the proper expansions.

If no quotes are detected on the line, return the result of expanding it with the default delegate (for unquoted text).

Otherwise break the line on the first set of (matching) quotes.

Any text defined before the beginning quote must be unquoted; apply the default expansion from from the table.

The text between the matching quotes is quoted, apply the appropriate expansion form the table (i.e. ‘, “, or `).

Any text remaining after the matching quotes may or may not be quoted; invoke expand_quotes() on the remainder to find out, and apply the result.

Each expansion applied is pushed onto the token stack in the escaped form it expanded to (i.e. “‘hi bye'” becomes “hi bye”), and the stack is returned to the caller once processing is completed.

With refactoring, the procedure could likely be made tail recursive but I don’t think perl does TCO. Either way, the users fingers or (likely) the machine generating the inputs should run out of stack space before tpsh could pop a cork at the number of quotes lol. An earlier design for expand_quotes() had more in common with finite state machines (in so far as I’ve seen them implemented), but was a lot more contorted then expand_quotes()’ present shape :-/.

Current bugs are handling nested escaped quotes or multiple empty quotes (the spliter) and removing unquoted quotes (addition to delegate sub for unquoted text).

# bugs in expand_quotes
$ echo 'foo "bar'
expand_quotes ': echo | foo "bar |
foo "bar
$ echo "foo "bar"
expand_quotes ": echo | foo | bar"
foo bar"
#
# correct result would have been equal to the previous command
#
$ echo '' "" '' "" '""' '' "" '"' "'"
expand_quotes ': echo | | "" '' "" '""' '' "" '"' "'"
expand_quotes ": " | '' | " '""' '' "" '"' "'"
expand_quotes ': " | "" | '' "" '"' "'"
expand_quotes ': ' | "" | "' "'"
expand_quotes ": "' | ' |
" '' " "" ' "" "' '
#
# correct result would have been: "" " '
# at least, that's how all bourne based shells I
# know about treat it; I would prefer: "" " '
# i.e. without leading whitespace.
#

For some reason this makes me curious, has anyone ever explained why shell syntax allows “”” but not ”’ ? (the results being ” and unclosed quote /or syntax error respectively)

When trying to solve a programming problem, generally I try the most simple solution before I try something more complex: and then evaluate a neater method. I consider the implications solutions have on efficiency, but that is trying to avoid shooting myself in the foot later, rather then trying to optimize the code for a machine.

Some how, I think expanding quotes is just naturally recursive in my crazy brain :-D.

EDIT


commit aeac14bd177a93b84c138a0c62e2cda49e5fe15c
Author: Terry <***snip***>
Date: Tue Apr 7 22:24:35 2009 +0000

bugfix: parameters now expand within quotes via expand_quotes and may be escaped

commit 089fda7cca0049dcabdc8b9659f94dcae417074b
Author: Terry <***snip***>

bugfix: escaped quotes witihn quotes and multiple quotes handled correctly

previous behaviour:

$ echo 'foo "bar'
expand_quotes ': echo | foo "bar |
foo "bar
$ echo "foo "bar"
expand_quotes ": echo | foo | bar"
foo bar"
$ echo '' "" '' "" '""' '' "" '"' "'"
expand_quotes ': echo | | "" '' "" '""' '' "" '"' "'"
expand_quotes ": " | '' | " '""' '' "" '"' "'"
expand_quotes ': " | "" | '' "" '"' "'"
expand_quotes ': ' | "" | "' "'"
expand_quotes ": "' | ' |
" '' " "" ' "" "' '
$

new behaviour:

$ echo 'foo "bar'
expand_quotes ': echo | foo "bar |
foo "bar
$ echo "foo "bar"
expand_quotes ": echo | foo "bar |
foo "bar
$ echo '' "" '' "" '""' '' "" '"' "'"
expand_quotes ': echo | | "" '' "" '""' '' "" '"' "'"
expand_quotes ": | | '' "" '""' '' "" '"' "'"
expand_quotes ': | | "" '""' '' "" '"' "'"
expand_quotes ": | | '""' '' "" '"' "'"
expand_quotes ': | "" | '' "" '"' "'"
expand_quotes ': | | "" '"' "'"
expand_quotes ": | | '"' "'"
expand_quotes ': | " | "'"
expand_quotes ": | ' |
"" " '
$

Awhile back I stumbled over a macro program for Win32, but lost track of it; found it again today: http://www.autohotkey.com/

I’ve been missing such abilities under Win32, and ain’t about to swap my old PS/2 keyboard for one of them fancy G15s lol.

recent activity

Terry@dixie$ cat lj.post
*Finally* started work on updating my laptop today; got world/kernel done. Set to work on the third party software, this tiem out employing portmaster for the task. To conserve CPU cycles, since that’s my laptops principal bellyache (along with the shitty graphics card); I’m currently running from a screen session on a vtty (i.e. Text Mode only).

For me, that’s actually not a big loss: only programs I’m missing out on are pidgin and firefox; and I _hate_ firefox these days. Most of the /good/ stuff I use all the time just happens to be console user friendly 😉
EOF

great surprise this morning, I’m off today and working tomorrow instead (glad I didn’t make plans lol). Since I had portmaster fetch distfiles a head of time, that also means I can continue my laptops software updates without lagging my game play to much hehe.

Right now I’ve got Dixie perched on my stand, and a SSH connection to her – with GNU Screen running, so I can always detach the session and reconnect to things from another box, or straight from Dixie’s console. I don’t think portmaster can be left unobserved as long as the portupgrade utility, but I think it is doing quite a good job of things: the need for a little hand holding aside. (I’m not interested in braving the “unattended mode” warning on our first date ^_^). I’ve also noted that perl modules can make upgrading perl a pain in the rear end; probably will have to take a manifest manually, then setup the automata to handle the unautomated part of the update procedure. All in all though, it’s been very painless.

Because of the way Vim implements Perl/Python/Ruby/probably the Tcl support; and my chose to build a ‘threaded perl’, I need to rebuild vim before it can be used. Never the less, I managed to fix the show-stopping bug in tpsh’s new expand_quotes() function — one darn question mark ‘?’ was missing; the difference making the regex non greedy. Although I rarely use any of the “extensions” in nvi’s command set, their chose of making :Next open in a separate display window sometimes comes in handy.

I’ve also been contemplating the sam text editor, as a possible replacement for ed/ex; the Q is does it offer suitable history support. My only complaint about ed and ex, is you can’t do thinks like ^NCR to repeat the last command (I wonder if GNU ed might’ve stuck that in, mm). Using vims “special” ex mode via gQ rather then vim -e or ‘Q’ gains all of the niceties of vim’s :ex command line, but if ones gonna run a visual editor that big; why go line mode without a pure TTY? lol.

FreeBSD dixie.launchmodem.com 7.2-PRERELEASE FreeBSD 7.2-PRERELEASE #3: Mon Apr 6 22:19:37 UTC 2009 root@dixie.launchmodem.com:/usr/obj/usr/src/sys/VIPER i386

Flitations with /bin/ed

lately, I’ve been developing a strange affection for the old ed(1) text editor. Because tpsh defaults the value of EDITOR to ed on unix, and edit on windows; I’ve had to deal with ed quite a lot whilst working on my shells ‘fc’ built-in (fc is the command for listing and editing/re-executing commands through the shells history).

Of course once support for ENV was worked out, I changed it to ex >_>

atm I’m reading the ed tutorial in ed, via ssh to my OpenBSD machine; it actually makes a nice pager :-/. All in all, I don’t think I would take ed over vi for coding but it’s a rather interesting program; after starting vim it’s also possible to drop into extended ex mode with gQ, effectively giving a modernized line editor.

My interest in ed atm is for short editing tasks, the kind where vi and other screen editors are not often necessary for the task. Some times, I can’t help but wonder if I’m secretly older then my birth date suggests lol.

mmm.

rofl

http://thedailywtf.com/Articles/The-Super-Hacker.aspx

on man, this ones got me rolling on the floor laughing my butt off – what a great way to make a buck