<?xml version="1.0"?>
<!-- name="generator" content="blosxom/2.0" -->
<!DOCTYPE rss PUBLIC "-//Netscape Communications//DTD RSS 0.91//EN" "http://my.netscape.com/publish/formats/rss-0.91.dtd">

<rss version="0.91">
  <channel>
    <title>Kragen's Blog Thing   </title>
    <link>http://www.bentwookie.org/blog</link>
    <description>Kragen's Blog Thing.</description>
    <language>en</language>

  <item>
    <title>silly English CFG sentence enumeration</title>
    <link>http://www.bentwookie.org/blog/2008/07/05#000492</link>
    <description>

&lt;PRE&gt;#!/usr/bin/python
import re, sys, StringIO
&amp;quot;&amp;quot;&amp;quot;Enumerate sentences of a context-free grammar.

Some sample, and kind of creepy, output:

Python writes this.
Python writes Python.
Python writes code.
Python writes you.
Python writes me.
...
the Python is code.
the Python is you.
the Python is me.
the code writes this.
...
6 lines are Python.
6 lines are code.
6 lines are you.
6 lines are me.
the generators are this.
the generators are Python.
...
by contrast, this is code.
by contrast, this is you.
by contrast, this is me.
the Python writes 6 generators.
the Python writes 6 lines.
the Python writes the generators.
the Python writes the lines.
...
by contrast, the lines are Python.
by contrast, the lines are code.
by contrast, the lines are you.
by contrast, the lines are me.
...
6 generators let you think me.
6 generators let me write this.
6 generators let me write Python.
...
the lines let Python think this.
the lines let Python think Python.
...
by contrast, the code writes the generators.
by contrast, the code writes the lines.
by contrast, the code is 6 generators.
by contrast, the code is 6 lines.
...
Python writes the Python code generators.
Python writes the Python code lines.
...
code writes 6 lines of code.
code writes 6 lines of you.
code writes 6 lines of me.
code writes the generators of this.
code writes the generators of Python.
code writes the generators of code.
code writes the generators of you.
code writes the generators of me.
&amp;quot;&amp;quot;&amp;quot;

default_cfg = '''
sentence &amp;quot;.&amp;quot;

sentence:
        singular-subject &amp;quot; &amp;quot; singular-predicate
        plural-subject &amp;quot; &amp;quot; plural-predicate
        sentence-modifier &amp;quot;, &amp;quot; sentence
sentence-modifier:
        &amp;quot;by contrast&amp;quot;
plural-subject:
        plural-noun
singular-subject:
        mass-noun
        singular-subject-pronoun
        &amp;quot;the &amp;quot; mass-noun
singular-subject-pronoun:
        &amp;quot;that&amp;quot;
        &amp;quot;this&amp;quot;
mass-noun:
        &amp;quot;Python&amp;quot;
        &amp;quot;code&amp;quot;
plural-noun:
        number &amp;quot; &amp;quot; simple-plural-noun
        plural-article &amp;quot; &amp;quot; simple-plural-noun
        plural-noun &amp;quot; &amp;quot; prepositional-phrase
plural-article:
        &amp;quot;the&amp;quot;
singular-article:
        &amp;quot;a&amp;quot;
        plural-article
prepositional-phrase:
        preposition &amp;quot; &amp;quot; object
preposition:
        &amp;quot;of&amp;quot;
simple-plural-noun:
        mass-noun &amp;quot; &amp;quot; simple-plural-noun
        &amp;quot;generators&amp;quot;
        &amp;quot;lines&amp;quot;
number:
        &amp;quot;6&amp;quot;
plural-predicate:
        plural-transitive-verb-phrase &amp;quot; &amp;quot; object
plural-transitive-verb-phrase:
        &amp;quot;let &amp;quot; object &amp;quot; &amp;quot; infinitive
        &amp;quot;are&amp;quot;
infinitive:
        &amp;quot;write&amp;quot;
        &amp;quot;think&amp;quot;
object:
        &amp;quot;this&amp;quot;
        plural-noun
        mass-noun
        &amp;quot;you&amp;quot;
        &amp;quot;me&amp;quot;
singular-predicate:
        singular-transitive-verb-phrase &amp;quot; &amp;quot; object
singular-transitive-verb-phrase:
        &amp;quot;writes&amp;quot;
        &amp;quot;is&amp;quot;
'''


class Literal:
    &amp;quot;A literal string in the grammar.&amp;quot;
    def __init__(self, contents):
        self.contents = contents.replace(r&amp;quot;\n&amp;quot;, &amp;quot;\n&amp;quot;)
    def alternatives(self, nwords, grammar):
        if nwords == 1:
            yield self.contents

class Nonterminal:
    &amp;quot;A nonterminal in the grammar; expands into some phrase.&amp;quot;
    def __init__(self, name):
        self.name = name
    def alternatives(self, nwords, grammar):
        for production in grammar[self.name]:
            for alternative in production.alternatives(nwords, grammar):
                yield alternative

class Concatenation:
    &amp;quot;A concatenation of two literals, nonterminals, and concatenations.&amp;quot;
    def __init__(self, left, right):
        self.left, self.right = left, right
    def alternatives(self, nwords, grammar):
        for ii in range(1, nwords):
            for left_alt in self.left.alternatives(ii, grammar):
                for right_alt in self.right.alternatives(nwords - ii,
                                                         grammar):
                    yield left_alt + right_alt

def concatenation(items):
    &amp;quot;Produce a concatenation of an arbitrary nonzero number of terms.&amp;quot;
    assert len(items) &amp;gt; 0
    if len(items) == 1: return items[0]
    elif len(items) == 2: return Concatenation(items[0], items[1])
    else: return Concatenation(items[0], concatenation(items[1:]))

def parse_production(line):
    &amp;quot;Turn a production line into a Concatenation, Nonterminal, or Literal&amp;quot;
    tokens = re.findall(r'\s*([-\w]+|&amp;quot;(?:[^&amp;quot;\\]|\\.)+&amp;quot;)', line)
    rv = []
    for tok in tokens:
        if tok.startswith('&amp;quot;'):
            rv.append(Literal(tok[1:-1]))
        else:
            rv.append(Nonterminal(tok))
    return concatenation(rv)

class CouldntParse(Exception): pass

class Grammar:
    &amp;quot;A container for the productions and the first rule.&amp;quot;
    def __init__(self, productions, first_rule):
        self.first_rule = first_rule
        self.productions = productions
    def __getitem__(self, x):
        return self.productions[x]
    def alternatives(self, nwords):
        return self.first_rule.alternatives(nwords, self)

def parse_grammar(infile):
    current_rule = None
    first_rule = None
    productions = {}
    for line in infile:
        if line.startswith(&amp;quot; &amp;quot;):
            productions[current_rule].append(parse_production(line))
        elif line.endswith(&amp;quot;:\n&amp;quot;):
            current_rule = line[:-2]
            productions[current_rule] = []
        elif re.match(r&amp;quot;\s*$&amp;quot;, line) or re.match(r'#', line):
            pass
        elif first_rule is None:
            first_rule = parse_production(line)
        else:
            raise CouldntParse(line)
    return Grammar(productions, first_rule)

if __name__ == '__main__':
    if len(sys.argv) == 1:
        infile = StringIO.StringIO(default_cfg)
    else:
        infile = file(sys.argv[1])
    grammar = parse_grammar(infile)
    ii = 0
    while True:
        for sentence in grammar.alternatives(ii):
            print sentence
        ii += 1


&lt;/PRE&gt;
</description>
  </item>
  <item>
    <title>worms.c: formatting of complicated conditionals</title>
    <link>http://www.bentwookie.org/blog/2008/07/03#001112</link>
    <description>

&lt;PRE&gt;* Kragen Javier Sitaker &amp;lt;&lt;A HREF=&quot;http://lists.canonical.org/mailman/listinfo/kragen-discuss&quot;&gt;kragen at canonical.org&lt;/A&gt;&amp;gt; [2008-07-03 09:40]:
&amp;gt;&lt;i&gt; I agree that the code needs rewriting, but inspired by Scheme,
&lt;/I&gt;&amp;gt;&lt;i&gt; I would do it without magic numbers, without nine separate
&lt;/I&gt;&amp;gt;&lt;i&gt; variables for the struct options pointers, and with conditions
&lt;/I&gt;&amp;gt;&lt;i&gt; and their consequents on the same line:
&lt;/I&gt;
Your version isn&amp;#8217;t tabular though. This is something I like about
both of the other rewrites better than yours. However, Spinellis
waffles on way too long to determine which array element to pick
and Steele commits the terrible sin of copypasting the x-related
conditional onto every one of the three lines.

Here&amp;#8217;s how I&amp;#8217;d fix both of these problems:

    struct options *locations[3][3] = {
         {upleft,  upper,  upright },
         {left,    normal, right   },
         {lowleft, lower,  lowright},
    };
    int h = x == last   ? 2 : !!x;
    int v = y == bottom ? 2 : !!y;
    op = &amp;amp;(locations[v][h])[w-&amp;gt;orientation];

This makes use of magic numbers and exploits the C type system
quirks relating to ints and boolean logic. Is that bad style?

Or is it idiomatic C?

In any case it&amp;#8217;s short enough to grasp quickly and the central
intent of the code is communicated visually by a table. I believe
quite strongly that code driven by tabular declarative sections,
even if the imperative part is somewhat tricky or even messy, is
easier to understand than simpler but more abstractly written code.

I do not see this as the be-all end-all version either, btw; if
there was a way to get the offset of a named member of a struct
in C, it would be possible to meld the advantages of your code
and mine. Think of the machine code that would be generated from
my code: there will multiplications with sizeof(options) in
there. The machine code version of your code would do the job
directly.

-- 
*AUTOLOAD=*_;sub _{s/(.*)::(.*)/print$2,(&amp;quot;,$\/&amp;quot;,&amp;quot; &amp;quot;)[defined wantarray]/e;$1}
&amp;amp;Just-&amp;gt;another-&amp;gt;Perl-&amp;gt;hack;
#Aristotle Pagaltzis // &amp;lt;&lt;A HREF=&quot;http://plasmasturm.org/&quot;&gt;http://plasmasturm.org/&lt;/A&gt;&amp;gt;
&lt;/PRE&gt;
</description>
  </item>
  <item>
    <title>worms.c: formatting of complicated conditionals</title>
    <link>http://www.bentwookie.org/blog/2008/07/03#000898</link>
    <description>

&lt;PRE&gt;// Diomidis Spinellis's book &amp;quot;Code Reading: An Open Source
// Perspective&amp;quot; has this messy code in chapter 2
// &amp;gt; &lt;A HREF=&quot;http://www.spinellis.gr/codereading/spinellisch02.pdf&quot;&gt;http://www.spinellis.gr/codereading/spinellisch02.pdf&lt;/A&gt;
// from netbsdsrc/games/worms/worms.c:419:

op = &amp;amp;(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) :
(x == last ? (!y ? upright : (y == bottom ? lowright : right)) :
(!y ? upper : (y == bottom ? lower : normal))))[w-&amp;gt;orientation];

// He rewrites it as follows, the idea being to improve its
// readability:

struct options *locations[3][3] = {
     {upleft, upper, upright},
     {left,    normal, right},
     {lowleft, lower, lowright},
};
int xlocation, ylocation;
// Determine x offset
if (x == 0)
     xlocation = 0;
else if (x ==  last)
     xlocation = 2;
else
     xlocation = 1;
// Determine y offset
if (y == 0)
     ylocation = 0;
else if (y ==  bottom)
     ylocation = 2;
else
     ylocation = 1;
op = &amp;amp;(locations[ylocation][xlocation])[w-&amp;gt;orientation];

// In my opinion, the above is actually worse than the original, as a
// result of being so much longer.  However, then Spinellis suggests
// this version, which he credits to Guy Steele:

op =
  &amp;amp;(        !y ? (!x ?  upleft : x!=last ?  upper :  upright ) :
     y!=bottom ? (!x ?    left : x!=last ? normal :    right ) :
                 (!x ? lowleft : x!=last ?  lower : lowright )
   )[w-&amp;gt;orientation];


// I agree that the code needs rewriting, but inspired by Scheme, I
// would do it without magic numbers, without nine separate variables
// for the struct options pointers, and with conditions and their
// consequents on the same line:

struct bar { struct options *left, *middle, *right } upper, middle, lower;
struct bar *a = (y == 0      ? &amp;amp;upper :
                 y == bottom ? &amp;amp;lower :
                               &amp;amp;middle);
struct options *b = (x == 0    ? a-&amp;gt;left  :
                     x == last ? a-&amp;gt;right :
                                 a-&amp;gt;middle);
op = &amp;amp;b[w-&amp;gt;orientation];
&lt;/PRE&gt;
</description>
  </item>
  <item>
    <title>double-ended log-structured filesystems</title>
    <link>http://www.bentwookie.org/blog/2008/06/30#000897</link>
    <description>

&lt;PRE&gt;I use a sort of log-structured filesystem for my notebooks.  I fill
the notebooks in chronological order (more or less) from the second
page to the last page.  (The first page is left blank at first.)
Everything is under some heading; the current heading is repeated at
the top of every page, with the date, but sometimes there are several
headings on a single page.  The headings are underlined so they're
easy to see looking at the page.

So I can find things by paging through the recent pages and looking at
the headings.  When that gets to be too much, I append a new &amp;quot;table of
previous contents&amp;quot; section, under a heading just like everything else;
it lists all the headings, with dates, since the last &amp;quot;table of
previous contents&amp;quot;.  The first page contains a list of tables of
previous contents, with their dates, so that I can find them
relatively quickly.  This allows me to find my notes more quickly by
reading through the few pages that are full of tables of previous
contents, rather than leafing through all the pages in the book
looking for headings.

If I were a disk, which I'm not, this would be a reasonably efficient
scheme for writes: regardless of how much stuff I have to write, I
could append it all in a single write to the end of the
currently-written data, possibly including a new table of previous
contents, then update the &amp;quot;superblock&amp;quot; on the first page with a
pointer to the new table.  So writing any amount of data less than a
notebookfull requires a seek to the end of the previous ToC, possibly
a read of data following it, a write of the new data, and possibly a
second seek and a second write to the superblock.  Two seeks.  Finding
something in a notebook with three ToCs requires at most four seeks:
one to each ToC, then another one to the data; if it's not listed in
any ToC, you can sequentially scan for it after the last ToC.

With this scheme, there's a tradeoff (for either humans or for disks)
between the amount of sequential scanning you may have to do (due to
still-unrubricated items) and the number of ToCs you may have to seek
to and read.

Beatrice pointed out the other day that it would be easier for a human
to write the notes sequentially from the beginning of the book, while
writing the ToC entries sequentially from the end of the book.  This
way, all the ToC entries are in a single sequential chunk, the
tradeoff between maximum sequential scan length and ToC fragmentation
is eliminated, and writing still requires only two seeks.

Of course she is correct, and this might be a reasonable strategy for
log-structured filesystems too, although there are usually more levels
of indirection: from superblock, through various levels of inodes and
directories, to the actual file extents on disk.  You could probably
do a reasonable job by putting a B-tree of pathnames at a fixed
location of the disk, and putting the inodes and data extents
contiguously somewhere else.  `/var/cache/locate/locatedb` is a
reasonable approximation of the contents of this B-tree; on my current
laptop, it's 5.3MB, indexing 95GB of files using 596 662 inodes
(i.e. 596 662 files, although `sudo locate / | wc -l` only finds 
494 488 files.).

Repacking a 5-20MB B-tree when it got too large and loose would take a
significant fraction of a second on a modern disk, but on my laptop
would take perhaps 10-20 seconds, due to the slowness of on-CPU disk
encryption.  So it might be better to defragment the tree incrementally.

&lt;/PRE&gt;
</description>
  </item>
  <item>
    <title>a few anecdotes</title>
    <link>http://www.bentwookie.org/blog/2008/06/28#000560</link>
    <description>

&lt;PRE&gt;I've been staying in Oakland, taking care of my cousin's house and
garden as he and his partner Becca visit family in New Mexico.

The other night, I ordered a carnitas burrito from a taco truck in a
parking lot at midnight, just after some Mexican-American teenagers
who talked to each other in English but ordered in Spanish.  They
breakdanced in the parking lot as other people, middle-aged men with
their toddler sons, young pregnant women with their young husbands or
boyfriends.  I felt very blessed to be there, under the flickery
yellow lights with the smell of many kinds of grilled meat wafting out
from the taco truck: lengua, carnitas, cabeza.  The burrito was
delicious; I ate it as I walked home.

***

Today, as I watered the garden, two young women drove up in a van full
of picnic supplies.  They turned out to be next-door neighbors I
hadn't met yet.  I was watering the green beans, occasionally munching
a succulent, sweet green pod.  When I initially said hello, they
didn't respond; I thought maybe they didn't speak English, so I told
them in Spanish how good the beans were and offered them some.  One of
them answered in English and accepted a pod, but didn't like it very
much.

***

Yesterday morning, I left their house at 7:30 so I wouldn't be late
for a meeting at HP Labs in Palo Alto at 10:00.  I stopped at the 16th
and Mission stop where I'd left Becca's bike the night before, with
both wheels and the frame locked to a parking meter, in between all
the other bicycles.  When I arrived, it was the only bike left; the
others had all left the night before.  Nothing was missing from it,
not even the pump and polyethylene water bottle.  But I missed my
connection at the 16th and Mission station, and I arrived at the
meeting at 10:45.

Unbeknownst to me, I had ruptured the rear inner tube riding it up to
HP Labs, and I had neglected to carry a tube repair kit with me ---
although there was one on the living room coffee table and one on the
shelf in the bedroom.  My friend Rohit gave me a ride to downtown with
the bike, where I bought tire levers and a patch kit, repaired the
tube, and broke the pump.

***

The other day, I wanted to make capresse sandwiches to share with my
friend Josh.  I picked fresh basil from the back yard and cut up some
tomatoes and mozzarella, but then discovered no bread.  But I had made
pancakes for breakfast with my friend Linley that morning.  So Josh
and I ended up having capresse sandwiches on cold pancakes made with
vanilla soy milk, on a rooftop plaza in the new San Francisco Public
Library building, accompanies with a garden salad from Ben and Becca's
garden, with nasturtium flowers, oxalis, arugula, purslane, and I
think a little mint, on top of some store-bought lettuce.

***

One day, on the way &amp;quot;home&amp;quot;, I stopped at the 16th and Mission station
to buy a phone card.  The $5 La Leyenda card I bought has provided
about 45 minutes of talk time to Beatrice in Argentina over the course
of more than a week.  I called her immediately before leaving the
phone-card store and talked for 15 of those minutes, because we hadn't
heard each other's voices in days.

&lt;/PRE&gt;
</description>
  </item>
  </channel>
</rss>