Tuesday, July 10, 2007

Portable compilers

I tried to put compilers of various languages into a USB thumb drive because some Windows machines don't have compilers.

  • Haskell: GHC has zipped version.
  • Erlang: Cean has zipped version. Only 3MB hoa!!!
  • Python: I couldn't find a zipped version but installation can be done without administrator privilege.
  • Java: Sun's JDK sucks. I need to be an admin to install it. JRockit can be installed without admin privilege.
  • Flex: Adobe releases zipped version. How nice of them?

Monday, July 9, 2007

Fcsh Server

I tried to make a wrapper to fcsh. The wrapper will have a socket open so that users can use netcat to talk to it. Possible usage would be like:

$ java FcshServer /opt/adobe/flex/bin/fcsh
$ echo "compile Game.as" | nc localhost 8081

Then FcshServer will see if Game.as has been already compiled. If it has, incremental compilation will be used. So far, I can wrap fcsh and send user inputs to stdin of fcsh and redirect fcsh's stdout to console.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.InputStreamReader;

public class FcshServer {
    public static void main(String argv[]) throws IOException {

        if(argv.length < 1) {
            System.out.println("Usage: java FcshServer path/to/fcsh");
            System.exit(1);
        }

        //run fcsh
        Process fcsh = new ProcessBuilder(argv).start();

        //redirect stdout of fcsh to here
        OutThread fcshout = new OutThread(fcsh);
        fcshout.start();

        //prepare for read from stdin of this.
        BufferedReader in = new BufferedReader(
                new InputStreamReader(System.in));
        String line = new String("");
        PrintWriter fcshin = new PrintWriter(fcsh.getOutputStream());

        while(fcshout.isAlive() && null != (line = in.readLine())) {
            fcshin.println(line);
            fcshin.flush();
        }

        in.close();
        fcshin.close();
    }
}

class OutThread extends Thread {
    private BufferedReader stdin;
    OutThread(Process p) throws IOException {
        stdin = new BufferedReader(
                new InputStreamReader(p.getInputStream()));
    }

    public void run() {
        int c;
        try {
            while((c = stdin.read()) != -1) {
                System.out.print((char)c);
            }
            System.out.println("Press Enter to exit.");
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}

Saturday, July 7, 2007

7777

2007 07 07 07pm

"a(a, b)" and "a (a, b)"

For Lipl, I can parse a(b c, d, e) and a (b c, d, e) differently. First is a function call while the second one is 2 tokens: Atom and List.

a = 1 .
b = 2 .
f(a, b) = [a + b] .
print f(a, b) .

If I have that, first appearance of f(a, b) should be distinguished from the second appearance after print. I can mark the declaration like: @f(a, b). But, even if I don't mark it as declaration, LiplMachine can look at the namespace for function f. If f doesn't exist it can be considered as a declaration. Or, I can always evaluate when a token is popped from the stack, not when it is pushed to. = f(a, b) [a + b] . is fine too because when f(a, b) is popped from the queue, not the stack, = is actually popping it. So, LipleMachine will know that f(a, b) is a declaration, not function call.

import pyparsing as pp
import sys

pp.ParseExpression.setDefaultWhitespaceChars("")

WS = pp.Suppress(pp.White())
OptWS = pp.Suppress(pp.Optional(WS))
LParen = pp.Suppress('(' + OptWS)
RParen = pp.Suppress(OptWS + ')')
Comma = pp.Suppress(OptWS + ',' + OptWS)

Atom = pp.Word(pp.alphas + '_', pp.alphanums + '_')\
        .setResultsName('Atom').setName('Atom')
Token = pp.Forward().setResultsName('Token')
Tokens = pp.Group(Token + pp.ZeroOrMore(WS + Token))\
        .setResultsName('Tokens').setName('Tokens')
CommaTokens = (Tokens + pp.ZeroOrMore(Comma + Tokens))\
        .setResultsName('CommaTokens').setName('CommaTokens')
List = pp.Group(LParen + CommaTokens + RParen)\
        .setResultsName('List').setName('List')
Funcall = pp.Group(Atom + List)\
        .setResultsName('Funcall').setName('Funcall')

Token << (List | Funcall | Atom)

S = (Tokens + pp.StringEnd())\
        .setResultsName('S').setName('S').leaveWhitespace()#.setDebug()

def print_tree(results, tab=2, level=0):
    "prints ParseResults"
    if type(results) != pp.ParseResults: #terminal
        print  (' '*level) + '> ' + str(results)
        return

    print (' '*level) + '- ' + results.getName() + ':'

    for x in results:
        print_tree(x, tab, level+tab)

def process(x):
    "parses and prints result"
    try:
        print x
        result = S.parseString(x)
        print ">>>", result
        print_tree(result)
        #result.dump()
        print ">>> [PASS]"
    except pp.ParseException, err:
        print x
        print (" " * (err.col - 1)) + "^"
        print err
        print ">>> [FAIL]"

def test(li):
    for x in li:
        process(x)

def main(argv=None):
    if argv is None:
        argv = sys.argv

    test(["a b (_a0, fun(arg1, arg2), a b (f,g),i)"])

    while True:
        line = raw_input("* ")
        if line == "q":
            print "Bye."
            sys.exit(0)
        process(line)

if __name__ == "__main__":
    main()

Wednesday, July 4, 2007

High level language

Java took away memory management from programmers so that they can concentrate on the problem itself.

Erlang took away thread management from programmers so that they don't have to clutter their algorithms with mutexes and stuff.

If we take away all those computer stuff from programming, the only thing left will be math equations. Or some arbitrary collection of symbols that carry our thoughts/algorithms.

So, I conjecture that in the future, programmers will program in a language similar to Prolog or Haskell but without all the computer juices. They will think and express in terms of relations, sets, and logic , but not in terms of machines, states, and operations. They will write programs in a way that order of expressions/statements doesn't matter. Any collection of expressions will be compiled in a way that each expression might be executed in parallel on different CPUs. And the programmer won't even think about underlying machines he/she is programming on.

Now, that pure language possibly can be used to describe semantics of any programming language.

Tuesday, July 3, 2007

Blog tools

So, this is a bash script that makes blogging easy.

#!/bin/sh

#prepares blog post using pandoc and xclip.

#path to programs used
SED=sed
PANDOC=pandoc
XCLIP=xclip
TEE=tee

if(( $# < 1 )); then
    echo "Usage: $0 <input file>"
    exit 1
fi

input="$1"

{
    echo '<div class="pandoc_wrap"><div class="pandoc_html">'
    $PANDOC -w html $input
    echo '</div><div class="pandoc_txt">'
    $SED 's/^/    /' $input | $PANDOC -w html
    echo '</div></div>'
} | tee >($XCLIP)

It creates a <div class="pandoc_wrap">, so you can use DOM to add a button to that div and make its children toggle. Here is example using JQuery:

function show_pandoc_html(pandoc_button) {
    pandoc_button.siblings('.pandoc_html').css('display', 'inline');
    pandoc_button.siblings('.pandoc_txt').css('display', 'none');
    pandoc_button.val('Markdown');
}

function show_pandoc_txt(pandoc_button) {
    pandoc_button.siblings('.pandoc_html').css('display', 'none');
    pandoc_button.siblings('.pandoc_txt').css('display', 'inline');
    pandoc_button.val('Html');
}

function attach_pandoc_button(pandoc_txt) {
    $('<input type="button" class="pandoc_button" value="Click"/><br/>')
        .toggle(function() { show_pandoc_html($(this)); }
                , function() { show_pandoc_txt($(this)); })
        .insertBefore(pandoc_txt.siblings('.pandoc_html'));
}

$(document).ready(function(){
    $('.pandoc_txt').each(function() { attach_pandoc_button($(this)); })
        .css('display', 'none');
});

I Love Pandoc

Pandoc is just amazing.

PKGBUILD

pkgver=0.3
pkgrel=1
pkgdesc="Pandoc is a Haskell library for converting from one markup format to another, and a command-line tool that uses this library. It can read markdown and (subsets of) reStructuredText, HTML, and LaTeX, and it can write markdown, reStructuredText, HTML, LaTeX, RTF, DocBook XML, and S5 HTML slide shows."
arch=('i686')
url="http://sophos.berkeley.edu/macfarlane/pandoc/index.html"
license=('GPL')
depends=('ghc')
makedepends=('make' 'sed')
source=("pandoc-${pkgver}.tar.gz")
md5sums=('08ea5da564b721bd3cd52eee316143a1')

build() {
    cd ${startdir}/src/pandoc-${pkgver}/
    make
    PREFIX=${startdir}/pkg/usr/ make install
}

test.txt

% Skynare
This is a [link](http://www.google.com/).

This is latex $(f: X \rightarrow Y)$

Then,

$ markdown2pdf test.txt
Created test.pdf

I tried reST but wasn't successful.

So, pandoc seems to be the blog preprocessing thingy.

$ pandoc blog.txt | xclip

Then, paste to blogger. Yay!

Monday, July 2, 2007

Jyntaxer

Everyone is making one of these. So, I thought I'd make one too using jquery.

First step in making something is to give it a name. I chose Jyntaxer because google didn't return a result (now, it will).

With JQuery, I can easily select $(".jyntaxer") and get .html() or .val() of the element. Then create a new element with .css("white-space", "pre") to make it look nice.

Since code usually contains <, > stuff, <textarea class="jyntaxer">some code with < > stuff</textarea> would be how normal user would use Jyntaxer.

Then I hit the wall: browser will render <textarea>&amp;</textarea> as &. If I query for that textarea.value, I get &. That means user has to preprocess their code before they can wrap their code in my magic <textarea class="jyntaxer">preprocessed code with &amp; properly escaped like &amp; => &amp;amp;</textarea>.

So, if user has to preprocess it, why not make the preprocessor highlight the syntax all together? Parsing strings in Javascript isn't fun.

So, Jyntaxer dies now

var KEYWORDS = ["abstract", "bool", "break", "case", "catch"
    , "char", "class", "const", "const_cast", "continue", "default"
    , "delete", "deprecated", "dllexport", "dllimport", "do", "double"
    , "dynamic_cast", "else", "enum", "explicit", "extern", "false", "float"
    , "for", "friend", "goto", "if", "inline", "int", "long", "mutable"
    , "naked", "namespace", "new", "noinline", "noreturn", "nothrow"
    , "novtable", "operator", "private", "property", "protected", "public"
    , "register", "reinterpret_cast", "return", "selectany", "short"
    , "signed", "sizeof", "static", "static_cast", "struct", "switch"
    , "template", "this", "thread", "throw", "true", "try", "typedef"
    , "typeid", "typename", "union", "unsigned", "using", "declaration"
    , "directive", "uuid", "virtual", "void", "volatile", "while", "typeof"
    , "as", "base", "by", "byte", "checked", "decimal", "delegate"
    , "descending", "event", "finally", "fixed", "foreach", "from", "group"
    , "implicit", "in", "interface", "internal", "into", "is", "lock"
    , "null", "object", "out", "override", "orderby", "params", "readonly"
    , "ref", "sbyte", "sealed", "stackalloc", "string", "select", "uint"
    , "ulong", "unchecked", "unsafe", "ushort", "var", "package"
    , "synchronized", "boolean", "implements", "import", "throws"
    , "instanceof", "transient", "extends", "final", "strictfp", "native"
    , "super", "debugger", "export", "function", "with", "NaN", "Infinity"
    , "require", "sub", "unless", "until", "use", "elsif", "BEGIN", "END"
    , "and", "assert", "def", "del", "elif", "except", "exec", "global"
    , "lambda", "not", "or", "pass", "print", "raise", "yield", "False"
    , "True", "Non", "e", "then", "end", "begin", "rescue", "ensure"
    , "module", "when", "undef", "next", "redo", "retry", "alias"
    , "defined", "done", "fi"];

function randint(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

//returns background style information of the node.
//if not defined, return parent's background style.
function getbg(node) {
    var bg = node.css("background-color");
    if(bg && bg != "transparent") {
        return bg;
    }
    return getbg(node.parent());
}

function getfg(bg) {
    var rgb = bg.match(/\d+/g);
    var fg = "rgb(";
    $.each(rgb, function (key, val) {
            fg += (Math.abs(randint(0, randint(0, 255) - Number(val, 10) + randint(0, 100))) + ',');
            });
    return fg.substring(0, fg.length - 1) + ')';
}

var JYN_STR_BEG = "0000JyntaxerStrBegin" + randint(1000, 9999);
var JYN_STR_END = "0000JyntaxerStrEnd" + randint(1000, 9999);

//node has raw code. converts it to html
function mkhtml(code) {

    var html = code.html();

    //html = html.replace(/(["'].*["'])/g
    //        , " " + JYN_STR_BEG + " $1 " + JYN_STR_END + " ");
    html = html.replace(/([a-zA-Z_]\w+)/g,
        function (str, p1, offset, s) {
            for(var i=0; i<KEYWORDS.length; i++) {
                if(p1 === KEYWORDS[i]) {
                    return "<span class=\"keyword\">"+p1+"</span>";
                }
            }
            return p1;
        });
    //html = html.replace(/\b(\d+)/g, "<span class=\"number\">$1</span>");
    //html = html.replace(new RegExp(JYN_STR_BEG, "g"), "<span class=\"string\">")
    //    .replace(new RegExp(JYN_STR_END, "g"), "</span>");

    //html = html.replace(/([^\w<>'" \s])/g, "<span class=\"operator\">$1</span>");
    //html = html.replace(/\n/g, "<br/>");
    //html = html.replace(/<.*\s(?!.*>)/g, "&nbsp;");
    var fg = getfg(getbg(code));

    html = $("<div class=\"jyntaxered\">" + html + "</div>");
    html.css("color", fg);
    $("#msg").append('<p>' + new Date() + ' : ' + code.attr("id") + '</p>');
    $("#msg").append($(html).each(function() { do_style($(this)); }));
    return html;
}

function do_style(node) {
    node.css("white-space", "pre");
    node.children(".keyword").css("color", "#ff0");
    node.children(".number").css("color", "#0ff");
    node.children(".string").css("color", "#f0f");
    node.children(".operator").css("color", "#00f");
}

//generates syntax highlighted code
function button_click(button, code) {
    if(button.attr("value") === "Jyntaxer") {
        code.css("display", "none");
        code.siblings(".jyntaxered:eq(0)").remove();
        mkhtml(code)
            .each(function () { do_style($(this)); }).insertAfter(code);

        button.attr("value", "Back");
    } else {
        code.css("display", "inline");
        code.siblings(".jyntaxered:eq(0)").css("display", "none");
        button.attr("value", "Jyntaxer");
    }
}

function show_code(button) {
    var code = button.siblings(".jyntaxer:eq(0)");
    var html = button.siblings(".jyntaxered:eq(0)");
    code.css("display", "inline");
    html.css("display", "none");
}
function show_html(button) {
    var code = button.siblings(".jyntaxer:eq(0)");
    var html = button.siblings(".jyntaxered:eq(0)");
    code.css("display", "none");
    html.css("display", "inline");
}

function attach_button(code) {
    $('<input type="button" class="jyntaxer_widget" value="Jyntaxer"/><br/>')
        .toggle(function() { show_html($(this)); }
                , function() { show_code($(this)); })
        .insertBefore(code);
}

function prepare_html(code) {
    code.wrap('<div class="jyntaxered_wrap"></div>');
    mkhtml(code).css("display", "none")
        .each(function () { do_style($(this)); }).insertAfter(code);
}

function is_outermost(node) {
    var parents = node.parents();
    var outermost = true;
    $.each(node.parents(), function (key, val) {
        if($(val).attr("class") === "jyntaxer") {
            outermost = false;
            return false;
        }});
    return outermost;
}

function jyntaxer() {
    $(".jyntaxer").filter(function () {
            return is_outermost($(this));
        }).each(function () {
            var code = $(this);
            prepare_html(code);
            attach_button(code);
            });
}

$(document).ready(function(){
    jyntaxer();
});

Html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-us" xml:lang="en-us" >
<head>
    <title>
        Jyntaxer : Javascript Syntax Highlight Thingy
    </title>
    <script type="text/javascript" src="jquery-latest.js"></script>
    <script type="text/javascript" src="jyntaxer.js"></script>
</head>
<body style="background: #aaa;">
<div id="container">
<p>
Hi this is some text.
</p>
<textarea id="python" class="jyntaxer" style="background-color: #fff;" cols="80" rows="20">
import sys

def html_escape(text
        , html_entities = {
            '&':'&amp;'
            , '<':'&lt;'
            , '>':'&gt;'
            #, "'":'''
            #, '"':'&quote;'
            , ' ':'&nbsp;'
            , '\t':'&nbsp;' } ):
    "replaces possible html entities in the text"
    l = []
    for c in text:
        l.append(html_entities.get(c,c))
    return "".join(l)

def main(argv=None):
    if argv is None:
        argv = sys.argv
    f = open(argv[1], 'r')
    print html_escape(f.read())

if __name__ == "__main__":
    main()
</textarea>
<p>
Hi this is some text.
</p>
<textarea id="cpp" class="jyntaxer" cols="80" rows="20">
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
int blah12 = 3435.453;
struct ScopeGuard: boost::function<void ()>, boost::noncopyable
{
  typedef boost::function<void ()> F;
  ScopeGuard () {}
  template <typename T> explicit ScopeGuard (T const & f) : F (f) {}
  ~ScopeGuard () { try { if (*this) operator()(); } catch (...) {} }
};
</textarea>
<p>
Hi this is some text.
</p>
</div>
<div id="msg"></div>
</body>
</html>