#!/usr/bin/perl

sub literal    ($);
sub emit       ($;$);
sub expression ();
sub error      ($);
sub parse      ();

my $emit;  # The output accumulator.
my $error; # The error message.

parse;     # Do it.

exit 0;    # Quit.

sub literal ($) {
    my $lit = $_[0];    # The literal string to be consumed.
    return s/^\s*\Q$lit\E\s*//;
}

sub emit ($;$) { # Consume input and (or just) emit output.
    unless ( $error ) {
        if ( @_ == 2 ) {
            my ( $in, $out ) = ( literal( $_[0] ), $_[1] );
            $emit .= $out if $in;
            return $in;
        } else {
            $emit .= $_[0]; # Just $out.
        }
    }
}

sub expression () {
    do {
        do {
            if ( literal '(' ) {
                emit '( ';
                expression;
                error 'missing )', return unless literal ')';
                emit ' )';
            } elsif ( literal 'not' ) {
                error 'empty negation', return if $_ eq '';
                emit '! ';
                expression;
            } else {
                if ( s/^\s*"(.+?)"\s*// || s/^\s*([^\s\)]+)\s*// ) {
                    my $word = $1;
                    if ( $word =~ /^(not|and|or)$/ ) {
                        error "word '$word' cannot be a search word", return;
                    } else {
                        emit "/$word/i";
                    }
		}
            } 
        } while emit 'and', ' && ';
    } while emit 'or', ' || ';
}

sub error ($) {
    my $msg = $_[0];
    $error = "$msg: $_" if $error eq '';
}

sub parse () {
    while ( <STDIN> ) {
        chomp;
        $emit = $error = '';
        expression;
        error 'illegal input' if $_ ne '';
        if ( $error eq '' ) {
            print "$emit\n";
        } else {
            warn "parse error: $error\n";
        }
    }
}
