Monday, April 12, 2010

I had never taken a serious look at the Python programming language, and I really only knew it for its usage of indentation for scoping. So I decided to try using it to implement an interpreter for my 01_ programming language, which I had implemented in Java, C, and Haskell earlier. It took a few days of my spare time.

Python is dynamically typed, and I don't like dynamic typing. The static typing of Haskell, and even Java, helps catch stupid little errors.

Python classes can't be used to create abstract data types, and only naming conventions and the double-underscore name-mangling hack are used to indicate (unenforcibly) private data.

I neither like nor dislike the syntactically significant indentation. It's just another syntax. However, if I had to work with large blocks of code, I'd prefer braces, because editors can match distant pairs of braces. But maybe people using Python would avoid writing large blocks of code. People using Java certainly do write large blocks of code, though.

Python has lots of nifty syntactical sugar enabling concise code, such as with statements, list comprehensions, and iterators. The generator coroutines for writing iterators is also nice for making readable code.

The Python library seems pretty comprehensive. I don't think it matches the Java library, but I haven't really looked at it.

In any case, I've demonstrated to myself that I can pick up a new programming language. Though, in the case of Python, I didn't learn any new programming concepts, certainly nothing mind-bending like call-with-current-continuation.

In line count, the 01_ interpreter in Python is about twice the size of the interpreter in Haskell, but about half the size of the interpreter in Java, and about a fourth the size of the interpreter in C.

import os
import sys

def tokens(chars):
lookahead = None
while True:
if lookahead == None:
char = chars.__next__()
else:
char = lookahead
lookahead = None
if char == '0' or char == '1' or char == '.' or char == '_':
yield char
elif char == '=':
try:
lookahead = chars.__next__()
except StopIteration:
yield '='
raise StopIteration
if lookahead != '=':
yield char
else:
lookahead = None
while chars.__next__() != '\n':
pass
elif char != ' ' and char != '\t' and char != '\r' and char != '\n':
symbol = char
while True:
try:
char = chars.__next__()
except StopIteration:
yield symbol
raise StopIteration
if (char == '0' or char == '1' or char == '.' or char == '='
or char == '_' or char == ' ' or char == '\t'
or char == '\r' or char == '\n'):
yield symbol
lookahead = char
break
else:
symbol = symbol + char

class LiteralExpr:
def __init__(self, bits):
self.bits = bits

class BoundExpr:
def __init__(self, index):
self.index = index

class ConcatExpr:
def __init__(self, head, tail):
self.head = head
self.tail = tail

class CallExpr:
def __init__(self, fn, args):
self.fn = fn
self.args = args

class ParseError(BaseException):
pass

class Pattern:
def __init__(self, match, binding, index):
self.match = match
self.binding = binding
self.index = index
def is_wild(self):
return self.binding == '.'
def is_literal(self):
return self.binding == '_'

class Defn:
def __init__(self, tokens):
self.name = tokens.__next__()
if self.name == '.' or self.name == '=' or self.name == '_' \
or self.name == '0' or self.name == '1':
raise ParseError
self.patterns = self._parse_patterns(tokens)
self.body = self._collect_body(tokens)

def _parse_patterns(self, tokens):
patterns = []
match = []
index = 0
while True:
token = tokens.__next__()
if token == '=':
if match != []:
patterns.append(Pattern(match, ".", None))
return patterns
elif token == '0':
match.append(False)
elif token == '1':
match.append(True)
elif token == '.' or token == '_':
patterns.append(Pattern(match, token, None))
match = []
else:
patterns.append(Pattern(match, token, index))
match = []
index = index + 1

def _collect_body(self, tokens):
body = []
while True:
token = tokens.__next__()
if token == '.':
return body
body.append(token)

def _arity(self, fns, name):
return len(fns[name][0].patterns) if name in fns else None

def _binding(self, patterns, name):
for pattern in patterns:
if name == pattern.binding:
return pattern.index
return None

def parse_body(self, fns):
if len(self.body) == 0:
self.expr = LiteralExpr([])
else:
self.expr = self._parse_exprs(self.body, 0, self.patterns, fns)
del self.body

def _parse_exprs(self, tokens, index, patterns, fns):
exp, index = self._parse_expr(tokens, index, patterns, fns)
if index >= len(tokens):
return exp
return ConcatExpr(exp, self._parse_exprs(tokens, index, patterns, fns))

def _parse_expr(self, tokens, index, patterns, fns):
token = tokens[index]
if token == '0' or token == '1' or token == '_':
return self._parse_literal(tokens, index)
binding = self._binding(patterns, token)
if binding != None:
return BoundExpr(binding), index + 1
arity = self._arity(fns, token)
if arity == None:
raise ParseError
args = []
index = index + 1
while len(args) < arity:
if index >= len(tokens):
raise ParseError
arg, index = self._parse_expr(tokens, index, patterns, fns)
args.append(arg)
return CallExpr(token, args), index

def _parse_literal(self, tokens, index):
bits = []
while True:
if index >= len(tokens):
return LiteralExpr(bits), index
elif tokens[index] == '0':
bits.append(False)
elif tokens[index] == '1':
bits.append(True)
elif tokens[index] == '_':
return LiteralExpr(bits), index + 1
else:
return LiteralExpr(bits), index
index = index + 1

def collect_defns(fns, tokens):
def defns_list():
while True:
yield Defn(tokens)
for defn in defns_list():
if defn.name in fns:
if len(fns[defn.name][0].patterns) != len(defn.patterns):
raise ParseError
fns[defn.name].append(defn)
else:
fns[defn.name] = [defn]

def parse_file(fns, file):
def chars():
for line in file:
for char in line:
yield char
collect_defns(fns, tokens(chars()))

def parse_bodies(fns):
for name, defns in fns.items():
for defn in defns:
defn.parse_body(fns)

class UndefinedFunctionError(BaseException):
pass

class NilVal:
def value():
return None

def next():
assert False

class LiteralVal:
def __init__(self, bits, index):
self._bits = bits
self._index = index
self._next = None

def value(self):
if self._index >= len(self._bits):
return None
else:
return self._bits[self._index]

def next(self):
if self._next == None:
assert self._index < len(self._bits)
self._next = LiteralVal(self._bits, self._index + 1)
return self._next

class FileVal:
def __init__(self, file, index = 7, byte = 0):
self._file = file
self._index = index
self._byte = byte
self._next = None

def value(self):
if self._byte == None:
assert self._index == 7
bytes = self._file.read(1)
if len(bytes) == 0:
self._byte = -1
self._file.close()
else:
self._byte = bytes[0]
if self._byte < 0:
return None
return (self._byte & (1 << self._index)) != 0

def next(self):
if self._next == None:
self.value()
assert self.value() != None
if self._index > 0:
self._next = FileVal(self._file, self._index - 1, self._byte)
else:
self._next = FileVal(self._file, 7, None)
return self._next

class ConcatVal:
def __init__(self, head, tail):
self._head = head
self._tail = tail
self._value = None
self._next = None

def value(self):
if self._head != None:
bit = self._head.value()
if bit != None:
self._value = bit
self._next = ConcatVal(self._head.next(), self._tail)
else:
self._value = self._tail.value()
if self._value != None:
self._next = self._tail.next()
self._head = None
self._tail = None
return self._value

def next(self):
if self._head != None:
self.value()
assert self._value != None
return self._next

class ExprVal:
def __init__(self, fns, expr, bindings):
self._fns = fns
self._expr = expr
self._bindings = bindings
self._value = None
self._next = None

def value(self):
if self._expr != None:
if self._expr.__class__ is LiteralExpr:
self._value, self._next = self._eval_literal()
elif self._expr.__class__ is BoundExpr:
self._value, self._next = self._eval_bound()
elif self._expr.__class__ is ConcatExpr:
self._value, self._next = self._eval_concat()
elif self._expr.__class__ is CallExpr:
self._value, self._next = self._eval_call()
else:
assert False
self._expr = None
return self._value

def next(self):
if self._expr != None:
self.value()
assert self._value != None
return self._next

def _eval_literal(self):
if self._expr.bits == []:
return None, None
else:
return self._expr.bits[0], LiteralVal(self._expr.bits, 1)

def _eval_bound(self):
val = self._bindings[self._expr.index]
bit = val.value()
return bit, val.next() if bit != None else None

def _eval_concat(self):
head = ExprVal(self._fns, self._expr.head, self._bindings)
tail = ExprVal(self._fns, self._expr.tail, self._bindings)
bit = head.value()
if bit != None:
return bit, ConcatVal(head.next(), tail)
else:
bit = tail.value()
return bit, tail.next() if bit != None else None

def _eval_call(self):
val = apply(self._fns, self._expr.fn,
[ExprVal(self._fns, arg, self._bindings)
for arg in self._expr.args])
bit = val.value()
return bit, val.next() if bit != None else None

def apply(fns, fn, args):
def match(pattern, val):
for bit in pattern.match:
b = val.value()
if b == None or b != bit:
return False
val = val.next()
if pattern.is_literal():
return val.value() == None
elif pattern.is_wild():
return True
else:
return val

for defn in fns[fn]:
bindings = []
for pattern, arg in zip(defn.patterns, args):
binding = match(pattern, arg)
if binding == False:
break
elif binding == True:
continue
else:
bindings.append(binding)
else:
return ExprVal(fns, defn.expr, bindings)
raise UndefinedFunctionError

def write_value(value, stream):
b = 0
bit = 128
while value.value() != None:
if value.value():
b = b | bit
if bit == 1:
stream.write(bytes([b]))
bit = 128
b = 0
else:
bit = bit >> 1
value = value.next()

def parse_sources(files):
fns = {}
for file in files:
with open(file) as f:
parse_file(fns, f)
parse_bodies(fns)
return fns

def interpreter():
source_files = []
fn = None
args = None
stdin = FileVal(sys.stdin.buffer)
for arg in sys.argv[1:]:
if fn == None:
if arg != '-':
source_files.append(arg)
else:
fn = os.path.basename(source_files[0])
if fn.find('.') > 0:
fn = fn[0:fn.find('.')]
elif args == None:
args = []
fn = arg
elif arg == '-':
args.append(stdin)
else:
args.append(FileVal(open(arg, "rb")))
if fn == None:
fn = os.path.basename(source_files[-1])
if fn.find('.') > 0:
fn = fn[0:fn.find('.')]
if args == None:
args = []
fns = parse_sources(source_files)
arity = len(fns[fn][0].patterns)
if len(args) < arity:
args.append(stdin)
while len(args) < arity:
args.append(NilVal())
write_value(apply(fns, fn, args[0:arity]), sys.stdout.buffer)

interpreter()

Monday, April 5, 2010

Here is a RESOL interpreter in Java. I originally wrote it as multiple files, but crammed it into a single file for this post. The input and output queue size is limited to 10. The interpreter in Haskell does not have this limitation.

import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

public class ri {
public static class RESOLException extends RuntimeException {
public RESOLException(Statement statement, String message) {
super(statement.getLocation() + ": " + message);
}

public RESOLException(Statement statement, String message, Throwable t) {
super(statement.getLocation() + ": " + message, t);
}

public RESOLException(String fileName, int lineNumber, String message) {
super(fileName + ":" + lineNumber + ": " + message);
}

public RESOLException(String fileName, int lineNumber, String message, Throwable t) {
super(fileName + ":" + lineNumber + ": " + message, t);
}
}

public static class BitInputStream {
private InputStream in;
private int currentByte;
private int currentBit = 0;
private boolean eof = false;

public BitInputStream(InputStream in) {
this.in = in;
}

public boolean eof() {
return eof;
}

public boolean read() throws IOException {
if (currentBit == 0) {
currentByte = in.read();
if (currentByte < 0) {
eof = true;
in.close();
return false;
}
currentBit = 128;
}
try {
return (currentByte & currentBit) != 0;
} finally {
currentBit >>>= 1;
}
}
}

public static class BitOutputStream {
private OutputStream out;
private int currentByte = 0;
private int currentBit = 128;

public BitOutputStream(OutputStream out) {
this.out = out;
}

public void write(boolean b) throws IOException {
if (b)
currentByte |= currentBit;
currentBit >>>= 1;
if (currentBit == 0) {
out.write(currentByte);
currentByte = 0;
currentBit = 128;
}
}
}

public static class Statement {
public enum Op { DATA, CALL, CONTINUE, IF, STOP }

private String fileName;
private int lineNumber;
private String label;
private Op op;
private String arg1;
private String arg2;
private Statement next = null;
private int itemSize = 0;
private LinkedList<LinkedList<Integer>> queueStack = null;
private LinkedList<Statement> callStack = null;

public Statement(String fileName, int lineNumber, String label, Op op, String arg1, String arg2) {
this.fileName = fileName;
this.lineNumber = lineNumber;
this.label = label == null || label.length() == 0 ? null : label;
this.op = op;
this.arg1 = arg1;
this.arg2 = arg2;
switch (op) {
case DATA:
if (arg1 == null)
throw new RESOLException(this, "DATA STATEMENT REQUIRES AN ARGUMENT");
if (label != null) {
itemSize = Integer.parseInt(arg1, 10);
queueStack = new LinkedList<LinkedList<Integer>>();
queueStack.addFirst(new LinkedList<Integer>());
if (arg2 != null)
enqueueLiteral(arg2);
}
break;
case CALL:
if (arg1 == null)
throw new RESOLException(this, "CALL STATEMENT REQUIRES AN ARGUMENT");
break;
case CONTINUE:
if (arg1 == null)
throw new RESOLException(this, "CONTINUE STATEMENT REQUIRES AN ARGUMENT");
break;
case IF:
if (arg1 == null || arg2 == null)
throw new RESOLException(this, "IF STATEMENT REQUIRES TWO ARGUMENTS");
break;
case STOP:
if (arg1 != null || arg2 != null)
throw new RESOLException(this, "STOP STATEMENT CANNOT HAVE ANY ARGUMENTS");
break;
}
if (label != null)
callStack = new LinkedList<Statement>();
}

protected String getFileName() {
return fileName;
}

protected int getLineNumber() {
return lineNumber;
}

public String getLabel() {
return label;
}

protected Op getOp() {
return op;
}

protected String getArg1() {
return arg1;
}

protected String getArg2() {
return arg2;
}

public void setNext(Statement next) {
this.next = next;
}

public String getLocation() {
return fileName + ":" + lineNumber;
}

public void enqueueLiteral(String literal) {
for (int i = 0; i < literal.length(); i++)
enqueueDigit(literal.charAt(i) - '0');
}

public void enqueueItem(LinkedList<Integer> queue, int queueItemSize) {
for (int i = 0; i < Math.min(queue.size(), queueItemSize); i++)
enqueueDigit(queue.get(i));
}

public void enqueueDigit(int digit) {
assert digit >= 0 && digit <= 9;
queueStack.getFirst().addLast(digit);
}

public void dequeueItem() {
for (int i = 0; i < itemSize && queueStack.getFirst().size() > 0; i++)
queueStack.getFirst().removeFirst();
}

public int getCurrentItemSize() {
return Math.min(itemSize, queueStack.getFirst().size());
}

public int getItemDigit(int index) {
assert index < itemSize;
return queueStack.getFirst().get(index);
}

public Statement popCall(Statement t, Statement n) {
if (queueStack != null)
queueStack.removeFirst();
return callStack.removeFirst();
}

public void pushCall(Statement t, Statement n) {
if (queueStack != null)
queueStack.addFirst(new LinkedList<Integer>());
callStack.addFirst(n);
}

public boolean isData() {
return op == Op.DATA;
}

private static void enqueueTo(Statement statement, String arg, Map<String,Statement> labels) {
if (!statement.isData())
return;
Statement argStatement = labels.get(arg);
if (argStatement == null)
statement.enqueueLiteral(arg);
else
for (int i = 0; i < argStatement.getCurrentItemSize(); i++)
statement.enqueueDigit(argStatement.getItemDigit(i));
}

private static boolean equalTo(String arg1, String arg2, Map<String,Statement> labels) {
if (arg1.equals(arg2))
return true;
Statement statement1 = labels.get(arg1);
Statement statement2 = labels.get(arg2);
if (statement1 == null && statement2 == null)
return false;
if (statement1 != null && statement2 != null) {
if (statement1.getCurrentItemSize() != statement2.getCurrentItemSize())
return false;
for (int i = 0; i < statement1.getCurrentItemSize(); i++)
if (statement1.getItemDigit(i) != statement2.getItemDigit(i))
return false;
return true;
}
if (statement1 == null) {
statement1 = statement2;
arg2 = arg1;
}
if (statement1.getCurrentItemSize() != arg2.length())
return false;
for (int i = 0; i < arg2.length(); i++)
if (statement1.getItemDigit(i) != arg2.charAt(i) - '0')
return false;
return true;
}

public Statement run(Map<String,Statement> labels) {
Statement statement = null;
Statement statement2 = null;
switch (op) {
case DATA:
statement = labels.get(arg1);
if (statement == null || !statement.isData())
break;
if (arg2 == null)
statement.dequeueItem();
else
enqueueTo(statement, arg2, labels);
break;

case CALL:
statement = labels.get(arg1);
if (statement == null)
throw new RESOLException(this, "CALL TO UNKNOWN LABEL: " + arg1);
if (next == null)
throw new RESOLException(this, "UNEXPECTED END OF PROGRAM");
statement.pushCall(this, next);
if (arg2 != null)
enqueueTo(statement, arg2, labels);
return statement;

case CONTINUE:
statement = labels.get(arg1);
if (statement == null)
throw new RESOLException(this, "CONTINUE FROM UNKNOWN LABEL: " + arg1);
if (!statement.isData() || statement.getCurrentItemSize() == 0)
return statement.popCall(this, next);
if (arg2 == null)
return statement;
statement = labels.get(arg2);
if (statement == null)
throw new RESOLException(this, "CONTINUE FROM UNKNOWN LABEL: " + arg2);
return statement;

case IF:
if (!equalTo(arg1, arg2, labels)) {
if (next == null || next.next == null)
throw new RESOLException(this, "UNEXPECTED END OF PROGRAM");
return next.next;
}
break;

case STOP:
return null;
}
if (next == null)
throw new RESOLException(this, "UNEXPECTED END OF PROGRAM");
return next;
}
}

public static class FirstStatement extends Statement {
private boolean encodeOutput;
private boolean isIO;
private int[] inputItem = null;
private int inputItemSize;
private BitInputStream in;
private int[] outputItem = null;
private int outputItemSize;
private BitOutputStream out;
private int itemBitCount;

public FirstStatement(Statement statement, boolean encodeOutput) {
super(statement.getFileName(), statement.getLineNumber(), statement.getLabel(), statement.getOp(), statement.getArg1(), statement.getArg2());
this.encodeOutput = encodeOutput;
isIO = getLabel() != null && getOp() == Op.DATA;
if (isIO) {
int itemSize = Integer.parseInt(getArg1(), 10);
inputItem = new int[itemSize];
inputItemSize = 0;
in = new BitInputStream(System.in);
outputItem = new int[itemSize];
outputItemSize = 0;
out = new BitOutputStream(System.out);

int test = 0;
for (int i = 0; i < itemSize; i++)
test = test*10 + 9;
itemBitCount = 0;
boolean decCount = false;
while (test > 0) {
if ((test & 1) == 0)
decCount = true;
test >>>= 1;
itemBitCount++;
}
if (decCount)
itemBitCount--;
}
}

public void enqueueDigit(int digit) {
if (!encodeOutput) {
System.out.print(digit);
return;
}
outputItem[outputItemSize++] = digit;
if (outputItemSize >= outputItem.length)
flushOutput();
}

public void flushOutput() {
int item = 0;
for (int i = 0; i < outputItem.length; i++)
item = item*10 + outputItem[i];
int bit = 1 << (itemBitCount - 1);
while (bit != 0) {
try {
out.write((item & bit) != 0);
} catch (IOException e) {
throw new RESOLException(this, "IO EXCEPTION", e);
}
bit >>>= 1;
}
outputItemSize = 0;
Arrays.fill(outputItem, 0);
}

public void dequeueItem() {
readItem();
}

public int getCurrentItemSize() {
if (inputItemSize == 0)
readItem();
return inputItemSize;
}

public int getItemDigit(int index) {
return inputItem[index];
}

private void readItem() {
inputItemSize = 0;
if (in.eof())
return;
int item = 0;
int bit = 1 << (itemBitCount - 1);
while (!in.eof() && bit != 0) {
boolean b;
try {
b = in.read();
} catch (IOException e) {
throw new RESOLException(this, "IO EXCEPTION", e);
}
if (in.eof())
break;
if (b)
item |= bit;
bit >>>= 1;
}
for (int i = inputItem.length - 1; i >= 0; i--) {
inputItem[i] = item%10;
item = item/10;
}
inputItemSize = inputItem.length;
}

public Statement popCall(Statement t, Statement n) {
if (!isIO)
return super.popCall(t, n);
if (n == null)
throw new RESOLException(t, "UNEXPECTED END OF PROGRAM");
return n;
}

public void pushCall(Statement t, Statement n) {
if (isIO)
throw new RESOLException(t, "ILLEGAL CALL");
super.pushCall(t, n);
}
}

public static class Parser implements Iterable<Statement>, Iterator<Statement> {
private Reader in;
private String fileName;
private int lineNumber;
private int statementLineNumber = 1;
private StringBuilder currentLabel = new StringBuilder();
private StringBuilder currentStatement = new StringBuilder();
private Statement statement = null;
private boolean eof = false;

public Parser(String fileName) throws IOException {
this(fileName, new FileReader(fileName));
}

public Parser(String fileName, Reader in) {
this.fileName = fileName;
this.in = in;
this.lineNumber = 0;
}

public Iterator<Statement> iterator() {
return this;
}

public boolean hasNext() {
while (statement == null && !eof)
try {
readLine();
} catch (IOException e) {
throw new RESOLException(fileName, lineNumber, "IO EXCEPTION", e);
}
return statement != null;
}

public Statement next() {
hasNext();
try {
return statement;
} finally {
statement = null;
}
}

public void remove() {
}

private void readLine() throws IOException {
lineNumber++;
int column = 1;
int c = in.read();
if (c < 0) {
eof = true;
in.close();
finishStatement();
return;
}
if (c == 'C') {
finishStatement();
statementLineNumber++;
while (c >= 0 && c != '\n')
c = in.read();
if (c < 0) {
eof = true;
in.close();
}
return;
}
StringBuilder sb = new StringBuilder();
while (column < 6) {
if (c != ' ') {
if (isDigit(c))
sb.append((char) c);
else
throw new RESOLException(fileName, lineNumber, "ILLEGAL LABEL");
}
c = in.read();
column++;
if (c < 0) {
eof = true;
in.close();
if (sb.length() > 0)
throw new RESOLException(fileName, lineNumber, "UNEXPECTED EOF");
finishStatement();
return;
}
if (c == '\n') {
finishStatement();
return;
}
}
if (c == ' ')
finishStatement();
currentLabel.append(sb);
for (;;) {
c = in.read();
column++;
if (c < 0) {
eof = true;
in.close();
finishStatement();
return;
}
if (c == '\n')
return;
if (c == ' ' || column > 72)
continue;
if (isDigit(c) || isLetter(c) || c == ',')
currentStatement.append((char) c);
else
throw new RESOLException(fileName, lineNumber, "UNEXPECTED CHARACTER");
}
}

private boolean isDigit(int c) {
return c >= '0' && c <= '9';
}

private boolean isLetter(int c) {
return c >= 'A' && c <= 'Z';
}

private void finishStatement() {
assert statement == null;
if (currentStatement.length() == 0 && currentLabel.length() == 0) {
statementLineNumber = lineNumber;
return;
}
int i = 0;
while (i < currentStatement.length() && isLetter(currentStatement.charAt(i)))
i++;
Statement.Op op;
try {
op = Enum.valueOf(Statement.Op.class, currentStatement.substring(0, i));
} catch (IllegalArgumentException e) {
throw new RESOLException(fileName, statementLineNumber, "UNRECOGNIZED STATEMENT");
}
String arg1 = null;
int i2 = i;
while (i2 < currentStatement.length() && isDigit(currentStatement.charAt(i2)))
i2++;
if (i2 < currentStatement.length()) {
if (i2 == i || currentStatement.charAt(i2) != ',')
throw new RESOLException(fileName, statementLineNumber, "ILLEGAL ARGUMENT");
}
if (i < i2)
arg1 = currentStatement.substring(i, i2);
String arg2 = null;
i = i2 + 1;
i2 = i;
while (i2 < currentStatement.length() && isDigit(currentStatement.charAt(i2)))
i2++;
if (i2 < currentStatement.length())
throw new RESOLException(fileName, statementLineNumber, "ILLEGAL ARGUMENT");
if (i < i2)
arg2 = currentStatement.substring(i, i2);
statement = new Statement(fileName, statementLineNumber, currentLabel.toString(), op, arg1, arg2);
statementLineNumber = lineNumber;
currentLabel.setLength(0);
currentStatement.setLength(0);
}
}

public static void main(String[] args) throws Exception {
boolean encodeOutput = true;
int index = 0;
if (index < args.length && "-r".equals(args[index])) {
encodeOutput = false;
index++;
}
FirstStatement first = null;
Statement last = null;
HashMap<String,Statement> labels = new HashMap<String,Statement>();
for (; index < args.length; index++)
for (Statement s : new Parser(args[index])) {
if (first == null)
s = first = new FirstStatement(s, encodeOutput);
else if (last != null)
last.setNext(s);
last = s;
if (s.getLabel() != null) {
if (labels.containsKey(s.getLabel()))
throw new RESOLException(s, "DUPLICATE LABEL");
labels.put(s.getLabel(), s);
}
}
last = first;
while (last != null)
last = last.run(labels);
}
}

Monday, March 29, 2010

Here is a RESOL program that prints itself.

001 DATA1
DATA001,99999
CALL004,99999
CALL10000,0010
CALL10002
CALL002
STOP
002 DATA1
DATA002
DATA002,10001
DATA001,10001
DATA10001
CONTINUE002
004 DATA000066
CALL005,004
DATA004
CONTINUE004
005 DATA1
CALL10000,0010020002000200020002000211
006 IF005,0
CALL10000,0300
IF005,1
CALL10000,0301
IF005,2
CALL10000,0302
IF005,3
CALL10000,0303
IF005,4
CALL10000,0304
IF005,5
CALL10000,0305
IF005,6
CALL10000,0306
IF005,7
CALL10000,0307
CALL002
DATA005
CONTINUE005,006
C THIS IS A LIBRARY THAT CONVERTS 4-BIT ITEMS ENQUEUED INTO 10000 AS 2 DIGITS
C INTO 3-BIT ITEMS IN 1 DIGIT THAT ARE AVAILABLE AT 10001.
C CALL 10000 TO PROCESS ITEMS FROM 10000 INTO 10001.
C CALL 10002 TO FLUSH THE FINAL DANGLING BITS (0-2 BITS).
C IF 000002 IS A DATA STATEMENT, CALLING 10000 WILL DEQUEUE FROM IT. BEST
C NOT TO HAVE 000002 AS A LABEL (WHICH WOULD REQUIRE A CONTINUATION LINE).
10000 DATA 000002
IF 10003,11000
CALL 10100
IF 10003,11001
CALL 10110
IF 10003,11002
CALL 10120
DATA 10003
DATA 10000
CONTINUE 10000
10001 DATA 1
C FLUSH THE FINAL DANGLING BITS
10002 IF 10003,11000
CONTINUE 10002
DATA 10001,10004
DATA 10004
C REINITIALIZE 10003 TO 012
IF 10003,11001
DATA 10003
DATA 10003
DATA 10003,012
CONTINUE 10002
C 10003 HOLDS THE NUMBER OF DANGLING BITS
10003 DATA 1,012
C 10004 HOLDS THE VALUE OF THE DANGLING BITS
10004 DATA 1
C NO DANGLING BITS FROM BEFORE. LEAVES 1 DANGLING BIT FOR NEXT ITEM.
10100 IF 10000,12000
DATA 10001,11000
IF 10000,12000
DATA 10004,11000
IF 10000,12001
DATA 10001,11000
IF 10000,12001
DATA 10004,11004
IF 10000,12002
DATA 10001,11001
IF 10000,12002
DATA 10004,11000
IF 10000,12003
DATA 10001,11001
IF 10000,12003
DATA 10004,11004
IF 10000,12004
DATA 10001,11002
IF 10000,12004
DATA 10004,11000
IF 10000,12005
DATA 10001,11002
IF 10000,12005
DATA 10004,11004
IF 10000,12006
DATA 10001,11003
IF 10000,12006
DATA 10004,11000
IF 10000,12007
DATA 10001,11003
IF 10000,12007
DATA 10004,11004
IF 10000,12008
DATA 10001,11004
IF 10000,12008
DATA 10004,11000
IF 10000,12009
DATA 10001,11004
IF 10000,12009
DATA 10004,11004
IF 10000,12010
DATA 10001,11005
IF 10000,12010
DATA 10004,11000
IF 10000,12011
DATA 10001,11005
IF 10000,12011
DATA 10004,11004
IF 10000,12012
DATA 10001,11006
IF 10000,12012
DATA 10004,11000
IF 10000,12013
DATA 10001,11006
IF 10000,12013
DATA 10004,11004
IF 10000,12014
DATA 10001,11007
IF 10000,12014
DATA 10004,11000
IF 10000,12015
DATA 10001,11007
IF 10000,12015
DATA 10004,11004
CONTINUE 10100
C 1 DANGLING BIT FROM BEFORE. LEAVES 2 DANGLING BITS FOR NEXT ITEM.
10110 IF 10004,11000
CALL 10111
IF 10004,11004
CALL 10112
DATA 10004
CONTINUE 10110
C DANGLING 0 FROM BEFORE
10111 IF 10000,12000
DATA 10001,11000
IF 10000,12000
DATA 10004,11000
IF 10000,12001
DATA 10001,11000
IF 10000,12001
DATA 10004,11002
IF 10000,12002
DATA 10001,11000
IF 10000,12002
DATA 10004,11004
IF 10000,12003
DATA 10001,11000
IF 10000,12003
DATA 10004,11006
IF 10000,12004
DATA 10001,11001
IF 10000,12004
DATA 10004,11000
IF 10000,12005
DATA 10001,11001
IF 10000,12005
DATA 10004,11002
IF 10000,12006
DATA 10001,11001
IF 10000,12006
DATA 10004,11004
IF 10000,12007
DATA 10001,11001
IF 10000,12007
DATA 10004,11006
IF 10000,12008
DATA 10001,11002
IF 10000,12008
DATA 10004,11000
IF 10000,12009
DATA 10001,11002
IF 10000,12009
DATA 10004,11002
IF 10000,12010
DATA 10001,11002
IF 10000,12010
DATA 10004,11004
IF 10000,12011
DATA 10001,11002
IF 10000,12011
DATA 10004,11006
IF 10000,12012
DATA 10001,11003
IF 10000,12012
DATA 10004,11000
IF 10000,12013
DATA 10001,11003
IF 10000,12013
DATA 10004,11002
IF 10000,12014
DATA 10001,11003
IF 10000,12014
DATA 10004,11004
IF 10000,12015
DATA 10001,11003
IF 10000,12015
DATA 10004,11006
CONTINUE 10111
C DANGLING 1 FROM BEFORE
10112 IF 10000,12000
DATA 10001,11004
IF 10000,12000
DATA 10004,11000
IF 10000,12001
DATA 10001,11004
IF 10000,12001
DATA 10004,11002
IF 10000,12002
DATA 10001,11004
IF 10000,12002
DATA 10004,11004
IF 10000,12003
DATA 10001,11004
IF 10000,12003
DATA 10004,11006
IF 10000,12004
DATA 10001,11005
IF 10000,12004
DATA 10004,11000
IF 10000,12005
DATA 10001,11005
IF 10000,12005
DATA 10004,11002
IF 10000,12006
DATA 10001,11005
IF 10000,12006
DATA 10004,11004
IF 10000,12007
DATA 10001,11005
IF 10000,12007
DATA 10004,11006
IF 10000,12008
DATA 10001,11006
IF 10000,12008
DATA 10004,11000
IF 10000,12009
DATA 10001,11006
IF 10000,12009
DATA 10004,11002
IF 10000,12010
DATA 10001,11006
IF 10000,12010
DATA 10004,11004
IF 10000,12011
DATA 10001,11006
IF 10000,12011
DATA 10004,11006
IF 10000,12012
DATA 10001,11007
IF 10000,12012
DATA 10004,11000
IF 10000,12013
DATA 10001,11007
IF 10000,12013
DATA 10004,11002
IF 10000,12014
DATA 10001,11007
IF 10000,12014
DATA 10004,11004
IF 10000,12015
DATA 10001,11007
IF 10000,12015
DATA 10004,11006
CONTINUE 10112
C 2 DANGLING BITS FROM BEFORE. LEAVES NO DANGLING BITS FOR NEXT ITEM.
10120 IF 10004,11000
CALL 10121
IF 10004,11002
CALL 10122
IF 10004,11004
CALL 10123
IF 10004,11006
CALL 10124
DATA 10003,13012
DATA 10004
IF 10000,12000
DATA 10001,11000
IF 10000,12001
DATA 10001,11001
IF 10000,12002
DATA 10001,11002
IF 10000,12003
DATA 10001,11003
IF 10000,12004
DATA 10001,11004
IF 10000,12005
DATA 10001,11005
IF 10000,12006
DATA 10001,11006
IF 10000,12007
DATA 10001,11007
IF 10000,12008
DATA 10001,11000
IF 10000,12009
DATA 10001,11001
IF 10000,12010
DATA 10001,11002
IF 10000,12011
DATA 10001,11003
IF 10000,12012
DATA 10001,11004
IF 10000,12013
DATA 10001,11005
IF 10000,12014
DATA 10001,11006
IF 10000,12015
DATA 10001,11007
CONTINUE 10120
C DANGLING 00 FROM BEFORE
10121 IF 10000,12000
DATA 10001,11000
IF 10000,12001
DATA 10001,11000
IF 10000,12002
DATA 10001,11000
IF 10000,12003
DATA 10001,11000
IF 10000,12004
DATA 10001,11000
IF 10000,12005
DATA 10001,11000
IF 10000,12006
DATA 10001,11000
IF 10000,12007
DATA 10001,11000
IF 10000,12008
DATA 10001,11001
IF 10000,12009
DATA 10001,11001
IF 10000,12010
DATA 10001,11001
IF 10000,12011
DATA 10001,11001
IF 10000,12012
DATA 10001,11001
IF 10000,12013
DATA 10001,11001
IF 10000,12014
DATA 10001,11001
IF 10000,12015
DATA 10001,11001
CONTINUE 10121
C DANGLING 01 FROM BEFORE
10122 IF 10000,12000
DATA 10001,11002
IF 10000,12001
DATA 10001,11002
IF 10000,12002
DATA 10001,11002
IF 10000,12003
DATA 10001,11002
IF 10000,12004
DATA 10001,11002
IF 10000,12005
DATA 10001,11002
IF 10000,12006
DATA 10001,11002
IF 10000,12007
DATA 10001,11002
IF 10000,12008
DATA 10001,11003
IF 10000,12009
DATA 10001,11003
IF 10000,12010
DATA 10001,11003
IF 10000,12011
DATA 10001,11003
IF 10000,12012
DATA 10001,11003
IF 10000,12013
DATA 10001,11003
IF 10000,12014
DATA 10001,11003
IF 10000,12015
DATA 10001,11003
CONTINUE 10122
C DANGLING 10 FROM BEFORE
10123 IF 10000,12000
DATA 10001,11004
IF 10000,12001
DATA 10001,11004
IF 10000,12002
DATA 10001,11004
IF 10000,12003
DATA 10001,11004
IF 10000,12004
DATA 10001,11004
IF 10000,12005
DATA 10001,11004
IF 10000,12006
DATA 10001,11004
IF 10000,12007
DATA 10001,11004
IF 10000,12008
DATA 10001,11005
IF 10000,12009
DATA 10001,11005
IF 10000,12010
DATA 10001,11005
IF 10000,12011
DATA 10001,11005
IF 10000,12012
DATA 10001,11005
IF 10000,12013
DATA 10001,11005
IF 10000,12014
DATA 10001,11005
IF 10000,12015
DATA 10001,11005
CONTINUE 10123
C DANGLING 11 FROM BEFORE
10124 IF 10000,12000
DATA 10001,11006
IF 10000,12001
DATA 10001,11006
IF 10000,12002
DATA 10001,11006
IF 10000,12003
DATA 10001,11006
IF 10000,12004
DATA 10001,11006
IF 10000,12005
DATA 10001,11006
IF 10000,12006
DATA 10001,11006
IF 10000,12007
DATA 10001,11006
IF 10000,12008
DATA 10001,11007
IF 10000,12009
DATA 10001,11007
IF 10000,12010
DATA 10001,11007
IF 10000,12011
DATA 10001,11007
IF 10000,12012
DATA 10001,11007
IF 10000,12013
DATA 10001,11007
IF 10000,12014
DATA 10001,11007
IF 10000,12015
DATA 10001,11007
CONTINUE 10124
C CONSTANTS
11000 DATA 1,0
11001 DATA 1,1
11002 DATA 1,2
11003 DATA 1,3
11004 DATA 1,4
11005 DATA 1,5
11006 DATA 1,6
11007 DATA 1,7
12000 DATA 2,00
12001 DATA 2,01
12002 DATA 2,02
12003 DATA 2,03
12004 DATA 2,04
12005 DATA 2,05
12006 DATA 2,06
12007 DATA 2,07
12008 DATA 2,08
12009 DATA 2,09
12010 DATA 2,10
12011 DATA 2,11
12012 DATA 2,12
12013 DATA 2,13
12014 DATA 2,14
12015 DATA 2,15
13012 DATA 3,012
99999 DATA 40000,
+140300611002004021040524202304121002004010020040210405242023006014
+226071162344711620504010020040100201032024611414030064130344711623
+447102420040100200401004150123046061140300601402606014030460024200
+401002004010041501230460611403006014405040100200401002010320246114
+140300620242004010020040100515242365001214030062100200402104052420
+230412100200401002004021040524202300601440504010020040100201042025
+210114030062130304601403006102420040100200401004210125040460140304
+541423006014030412100200401002004021040524202304601403006102420040
+100200401004151723452111234525051403006202430060150200401004210125
+040460140300601543301210020040100200402064051423030060152260601403
+201210020040100200402104052420230060150050401002004010020103236471
+242224712521230060150050601403244010020104202521011420504010020040
+100201032024611414230060140300541403006114030062140300601443006014
+031060140300621403006014430060140310611420506014033040100201112143
+006015226060024200401002004010041501230460611403006014026060146300
+600242004010020040100445061403006513030412100200401002004020640514
+230304601403006013030063140304121002004010020040222430601403245414
+405040100200401002010320246114142300601403005414031460144050401002
+004010020111214300601522606302420040100200401004150123046061140300
+601402606014630063024200401002004010044506140300651303201210020040
+100200402064051423030460140300601303006314032012100200401002004022
+243060140324541520504010020040100201032024611414230060140300541403
+146015205040100200401002011121430060152260660242004010020040100415
+012304606114030060140260601463006602420040100200401004450614030065
+130334121002004010020040206405142303046014030060130300631403341210
+020040100200402064051423030060144050401002004010020104202521011403
+006502420040100200401004151723452111234525051403006513030060154051
+031005211022251440222514402022011422241122202511311005211020252040
+206475162544252225051440150265022225204022252105232514402124712125
+242525212420402224712423620061140300601402010124620062100421112164
+452424605103100445162504744014626502222520402225210523251440222470
+401422010422243511250201242204052410040522212201012544051123040502
+230424402025204014230060140304560244144020640514230200611403006014
+020124236201202444750321251523100445242124652310043122236464401423
+006014030040222471242362006114030060142270122062010320246114100304
+601403006210052117100431142525151010052110212201062224710123020104
+202471072304451621620102222521231002406013231040204445242462445602
+441440222430401403006014030062100445231004044021040524202201232504
+052421246505234520541004150123046111234434401423006014030040256445
+142302010421250525212525051004312223646440222520561002010221251524
+024414402344752410052117100441012544244014030060140300621004052310
+040440230405022124604012053510222415101005351725246104100511052425
+251124442440202201032364712422247125202521112364704023044516212244
+560243046014030060100421012504044014030060140300620242004010020040
+100445061003046014030063130304611403006002420040100200401004150123
+046040142300611403001210020040100200402224304014230060140314541423
+046014030412100200401002004020640514230200611403046114005040100200
+401002011121420061140300601462606114230060144050401002004010020103
+202461141003046014231060024200401002004010042101250404401423006014
+031412100200401002004021040524202200611403006014005040100200401002
+010323647124222471252122006114030060140050611403006014220104202521
+011003041220620106230525232202012422042440214445162024604021040516
+216461112344344020444524246050611403006014420111214200611403006014
+626061142300601400504010020040100201032364712422247125212200611403
+006014405040100200401002010420252101100304601403006113030460140300
+640242004010020040100421012504044014230060140320122062012221244516
+222521112024611126442440142300601403144025047440140304620242004010
+020040100445061003046014030063130304611403006102420040100200401004
+210125040440142300601403141210020040100200402104052420220061140300
+601460504010020040100201042025210110030460140300631303006114405040
+100200401002010323647124222471252122006114030060144051031003046014
+030063100441172304212310052110212201162524650221251040236430402104
+051621646111234434402044452424605061140300601462010420252101100304
+541403046202441440142300601403204022047514210514402504410510053101
+230525051004750610052110212201042024710723044516216201022225212302
+430460140300641004210125040440142051031004711710042101234435142224
+710710041111250514402145111723220102212431172444245610020114212405
+262125144014220104202471072304451621620102222520402144752210047105
+260520402225210523227012142300611403004022243040142300601403005414
+231060140300121002004010020040210405242022006114030060142260611423
+006014005040100200401002011121420061140300601402606114430060140050
+401002004010020104202521011003046014030064130304611403006002420040
+100200401004450610030460140300601303046214030061024200401002004010
+042101250404401423006014030454142304601403001210020040100200402224
+304014230060140300541423106014030412100200401002004021040524202200
+611403006015026061142300601500504010020040100201112142006114030060
+140260611443006014405040100200401002010420252101100304601403006113
+030461140300610242004010020040100445061003046014030060130304621403
+006202420040100200401004210125040440142300601403205414230460140300
+121002004010020040222430401423006014030054142310601403141210020040
+100200402104052420220061140300601422606114230060142050401002004010
+020111214200611403006014026061144300601460504010020040100201042025
+210110030460140300641303046114030064024200401002004010044506100304
+601403006013030462140300640242004010020040100421012504044014230060
+140304541423046014031012100200401002004022243040142300601403005414
+231060140320121002004010020040210405242022006114030060150260611423
+006014005040100200401002011121420061140300601402606114430060152050
+401002004010020104202521011003046014030061130304611403006202420040
+100200401004450610030460140300601303046214030065024200401002004010
+042101250404401423006014032054142304601403201210020040100200402224
+304014230060140300541423106014033012100200401002004021040524202200
+611403006014226061142300601460504010020040100201112142006114030060
+140260611443006015405040100200401002010420252101100304601403006413
+030461140300600242004010020040100445061003046014030060130304621403
+006702420040100200401004210125040440142300601403045414230460140314
+121002004010020040222430401423006014030054142310601403341210020040
+100200402104052420220061140300601502606114230060150050401002004010
+020111214200611403006014026061144300601600504010020040100201042025
+210110030460140300611303046114030064024200401002004010044506100304
+601403006013030462140300700242004010020040100421012504044014230060
+140320541423046014030012100200401002004022243040142300601403005414
+231060140344121002004010020040210405242022006114030060142260611423
+006015005040100200401002011121420061140300601402606114430060162050
+401002004010020104202521011003046014030064130304611403006402420040
+100200401004450610030460140300601303046214030460024200401002004010
+042101250404401423006014030454142304601403241210020040100200402224
+304014230060140300541423106014230012100200401002004021040524202200
+611403006015026061142300601400504010020040100201112142006114030060
+140260611443006114205040100200401002010420252101100304601403006113
+030461140300650242004010020040100445061003046014030060130304621403
+046102420040100200401004210125040440142300601403205414230460140320
+121002004010020040222430401423006014030054142310601423101210020040
+100200402104052420220061140300601422606114230060154050401002004010
+020111214200611403006014026061144300611440504010020040100201042025
+210110030460140300641303046114030060024200401002004010044506100304
+601403006013030462140304630242004010020040100421012504044014230060
+140304541423046014033012100200401002004022243040142300601403005414
+231060142314121002004010020040210405242022006114030060150260611423
+006015005040100200401002011121420061140300601402606114430061150050
+401002004010020104202521011003046014030061130304611403006702420040
+100200401004450610030460140300601303046214030464024200401002004010
+042101250404401423006014032054142304601403001210020040100200402224
+304014230060140300541423106014232412100200401002004021040524202200
+611403006014226061142300601560504010020040100201112142006114030060
+140260611443006115205040100200401002010420252101100304601403006413
+030461140300640242004010020040100415172345211123452505100304601423
+006002441440142201042024710723044516216201022225204021451117232201
+022124311724442456100201142124052621251440144201042024710723044516
+216201022225212310043117244201162125412410044524212464560243046014
+230460100445061003046014030064130304611403006002420040100200401004
+150123046040142300611423041210020040100200402224304014230060140320
+541423046014032012100200401002004020640514230200611403046114405040
+100200401002010420252101100304601403006402420040100200401004151723
+452111234525051003046014230460024414402104051621646111234434401402
+010624447515100411052144752221205061140304611422011121420061140300
+601402606114430060140050401002004010020104202521011003046014030061
+130304611403006002420040100200401004450610030460140300601303046214
+030060024200401002004010042101250404401423006014032054142304601403
+001210020040100200402224304014230060140300541423106014030412100200
+401002004021040524202200611403006014226061142300601400504010020040
+100201112142006114030060140260611443006014205040100200401002010420
+252101100304601403006413030461140300620242004010020040100445061003
+046014030060130304621403006202420040100200401004210125040440142300
+601403045414230460140300121002004010020040222430401423006014030054
+142310601403101210020040100200402104052420220061140300601502606114
+230060150050401002004010020111214200611403006014026061144300601460
+504010020040100201042025210110030460140300611303046114030060024200
+401002004010044506100304601403006013030462140300630242004010020040
+100421012504044014230060140320541423046014033012100200401002004022
+243040142300601403005414231060140320121002004010020040210405242022
+006114030060142260611423006014205040100200401002011121420061140300
+601402606114430060150050401002004010020104202521011003046014030064
+130304611403006002420040100200401004450610030460140300601303046214
+030065024200401002004010042101250404401423006014030454142304601403
+041210020040100200402224304014230060140300541423106014032412100200
+401002004021040524202200611403006015026061142300601440504010020040
+100201112142006114030060140260611443006015405040100200401002010420
+252101100304601403006113030461140300610242004010020040100445061003
+046014030060130304621403006602420040100200401004210125040440142300
+601403205414230460140320121002004010020040222430401423006014030054
+142310601403341210020040100200402104052420220061140300601422606114
+230060142050401002004010020111214200611403006014026061144300601560
+504010020040100201042025210110030460140300641303046114030066024200
+401002004010044506100304601403006013030462140300700242004010020040
+100421012504044014230060140304541423046014031012100200401002004022
+243040142300601403005414231060140340121002004010020040210405242022
+006114030060150260611423006014005040100200401002011121420061140300
+601402606114430060162050401002004010020104202521011003046014030061
+130304611403006202420040100200401004450610030460140300601303046214
+030071024200401002004010042101250404401423006014032054142304601403
+101210020040100200402224304014230060140300541423106014230012100200
+401002004021040524202200611403006014226061142300601440504010020040
+100201112142006114030060140260611443006114005040100200401002010420
+252101100304601403006413030461140300640242004010020040100445061003
+046014030060130304621403046102420040100200401004210125040440142300
+601403045414230460140310121002004010020040222430401423006014030054
+142310601423041210020040100200402104052420220061140300601502606114
+230060154050401002004010020111214200611403006014026061144300611440
+504010020040100201042025210110030460140300611303046114030063024200
+401002004010044506100304601403006013030462140304620242004010020040
+100421012504044014230060140320541423046014030012100200401002004022
+243040142300601403005414231060142314121002004010020040210405242022
+006114030060142260611423006014605040100200401002011121420061140300
+601402606114430061146050401002004010020104202521011003046014030064
+130304611403006202420040100200401004450610030460140300601303046214
+030464024200401002004010042101250404401423006014030454142304601403
+141210020040100200402224304014230060140300541423106014232012100200
+401002004021040524202200611403006015026061142300601500504010020040
+100201112142006114030060140260611443006115205040100200401002010420
+252101100304601403006113030461140300630242004010020040100445061003
+046014030060130304621403046502420040100200401004210125040440142300
+601403205414230460140330121002004010020040206475162504451625242440
+142300611423041220620104202471072304451621620061100431222364644020
+442506236511050243046014230462100445061003046014030060130304621403
+006002420040100200401004210125040440142300601403045414230460140320
+121002004010020040222430401423006014030054142310601403001210020040
+100200402104052420220061140300601502606114230060140050401002004010
+020111214200611403006014026061144300601420504010020040100201042025
+210110030460140300611303046114030064024200401002004010044506100304
+601403006013030462140300610242004010020040100421012504044014230060
+140320541423046014031012100200401002004022243040142300601403005414
+231060140310121002004010020040210405242022006114030060142260611423
+006015005040100200401002011121420061140300601402606114430060144050
+401002004010020104202521011003046014030064130304611403006402420040
+100200401004450610030460140300601303046214030063024200401002004010
+042101250404401423006014030454142304601403201210020040100200402224
+304014230060140300541423106014031412100200401002004021040524202200
+611403006015026061142300601540504010020040100201112142006114030060
+140260611443006015005040100200401002010420252101100304601403006113
+030461140300650242004010020040100445061003046014030060130304621403
+006402420040100200401004210125040440142300601403205414230460140300
+121002004010020040222430401423006014030054142310601403241210020040
+100200402104052420220061140300601422606114230060152050401002004010
+020111214200611403006014026061144300601520504010020040100201042025
+210110030460140300641303046114030062024200401002004010044506100304
+601403006013030462140300660242004010020040100421012504044014230060
+140304541423046014032412100200401002004022243040142300601403005414
+231060140330121002004010020040210405242022006114030060150260611423
+006015005040100200401002011121420061140300601402606114430060156050
+401002004010020104202521011003046014030061130304611403006502420040
+100200401004450610030460140300601303046214030067024200401002004010
+042101250404401423006014032054142304601403301210020040100200402224
+304014230060140300541423106014034012100200401002004021040524202200
+611403006014226061142300601540504010020040100201112142006114030060
+140260611443006016005040100200401002010420252101100304601403006413
+030461140300600242004010020040100445061003046014030060130304621403
+007102420040100200401004210125040440142300601403045414230460140330
+121002004010020040222430401423006014030054142310601403441210020040
+100200402104052420220061140300601502606114230060144050401002004010
+020111214200611403006014026061144300611400504010020040100201042025
+210110030460140300611303046114030066024200401002004010044506100304
+601403006013030462140304600242004010020040100421012504044014230060
+140320541423046014032012100200401002004022243040142300601403005414
+231060142304121002004010020040210405242022006114030060142260611423
+006015405040100200401002011121420061140300601402606114430061142050
+401002004010020104202521011003046014030064130304611403006602420040
+100200401004450610030460140300601303046214030462024200401002004010
+042101250404401423006014030454142304601403341210020040100200402224
+304014230060140300541423106014231012100200401002004021040524202200
+611403006015026061142300601400504010020040100201112142006114030060
+140260611443006114605040100200401002010420252101100304601403006113
+030461140300670242004010020040100445061003046014030060130304621403
+046302420040100200401004210125040440142300601403205414230460140310
+121002004010020040222430401423006014030054142310601423201210020040
+100200402104052420220061140300601422606114230060156050401002004010
+020111214200611403006014026061144300611500504010020040100201042025
+210110030460140300641303046114030064024200401002004010044506100304
+601403006013030462140304650242004010020040100421012504044014230060
+140304541423046014033412100200401002004022243040142300601403005414
+231060142324121002004010020040210405242022006114030060150260611423
+006015405040100200401002010323647124222471252122006114030461144051
+031003104021040516216461112344344020444524246201062444751510041105
+214475222122704010046105202531052462011623620104202471072304451621
+620102222521231004311724420116212541241004452421246456024304601423
+106010044506100304601403006413030461140300600242004010020040100415
+012304604014230061144304121002004010020040222430401423006014032054
+142304601403101210020040100200402064051423020061140304621440504010
+020040100201112142006114030060150260611423006015005040100200401002
+010320246114100304601423106302420040100200401004450610030460140300
+641303046114030066024200401002004010041501230460401423006114432012
+100200401002004021040524202200611403006014626061146300611440504010
+020040100201042025210110030460140300640242004010020040100445061003
+046014030060130304621403006002420040100200401004210125040440142300
+601403045414230460140300121002004010020040222430401423006014030054
+142310601403041210020040100200402104052420220061140300601422606114
+230060142050401002004010020111214200611403006014026061144300601440
+504010020040100201042025210110030460140300611303046114030062024200
+401002004010044506100304601403006013030462140300630242004010020040
+100421012504044014230060140304541423046014031412100200401002004022
+243040142300601403005414231060140320121002004010020040210405242022
+006114030060142260611423006015005040100200401002011121420061140300
+601402606114430060152050401002004010020104202521011003046014030061
+130304611403006502420040100200401004450610030460140300601303046214
+030066024200401002004010042101250404401423006014030454142304601403
+301210020040100200402224304014230060140300541423106014033412100200
+401002004021040524202200611403006014226061142300601560504010020040
+100201112142006114030060140260611443006016005040100200401002010420
+252101100304601403006113030461140300600242004010020040100445061003
+046014030060130304621403007102420040100200401004210125040440142300
+601403045414230460140304121002004010020040222430401423006014030054
+142310601423001210020040100200402104052420220061140300601422606114
+230060144050401002004010020111214200611403006014026061144300611420
+504010020040100201042025210110030460140300611303046114030063024200
+401002004010044506100304601403006013030462140304620242004010020040
+100421012504044014230060140304541423046014032012100200401002004022
+243040142300601403005414231060142314121002004010020040210405242022
+006114030060142260611423006015205040100200401002011121420061140300
+601402606114430061150050401002004010020104202521011003046014030061
+130304611403006602420040100200401004450610030460140300601303046214
+030465024200401002004010042101250404401423006014030454142304601403
+341210020040100200402064751625044516252424401423006114430012206201
+042024710723044516216200601402010624447515100411052144752221205061
+140304621422011121420061140300601402606114430060140050401002004010
+020104202521011003046014030061130304611403006002420040100200401004
+450610030460140300601303046214030061024200401002004010042101250404
+401423006014030454142304601403001210020040100200402224304014230060
+140300541423106014031012100200401002004021040524202200611403006014
+226061142300601400504010020040100201112142006114030060140260611443
+006014605040100200401002010420252101100304601403006113030461140300
+600242004010020040100445061003046014030060130304621403006402420040
+100200401004210125040440142300601403045414230460140300121002004010
+020040222430401423006014030054142310601403241210020040100200402104
+052420220061140300601422606114230060140050401002004010020111214200
+611403006014026061144300601540504010020040100201042025210110030460
+140300611303046114030060024200401002004010044506100304601403006013
+030462140300670242004010020040100421012504044014230060140304541423
+046014030012100200401002004022243040142300601403005414231060140340
+121002004010020040210405242022006114030060142260611423006014205040
+100200401002011121420061140300601402606114430060162050401002004010
+020104202521011003046014030061130304611403006102420040100200401004
+450610030460140300601303046214030460024200401002004010042101250404
+401423006014030454142304601403041210020040100200402224304014230060
+140300541423106014230412100200401002004021040524202200611403006014
+226061142300601420504010020040100201112142006114030060140260611443
+006114405040100200401002010420252101100304601403006113030461140300
+610242004010020040100445061003046014030060130304621403046302420040
+100200401004210125040440142300601403045414230460140304121002004010
+020040222430401423006014030054142310601423201210020040100200402104
+052420220061140300601422606114230060142050401002004010020111214200
+611403006014026061144300611520504010020040100201042025210110030460
+140300611303046114030061024200401002004010041517234521112345250510
+030460142310610244144021040516216461112344344014030440214511172322
+010221243117244424121423006114431040222430401423006014030054142310
+601403001210020040100200402104052420220061140300601422606114230060
+144050401002004010020111214200611403006014026061144300601420504010
+020040100201042025210110030460140300611303046114030062024200401002
+004010044506100304601403006013030462140300620242004010020040100421
+012504044014230060140304541423046014031012100200401002004022243040
+142300601403005414231060140314121002004010020040210405242022006114
+030060142260611423006014405040100200401002011121420061140300601402
+606114430060150050401002004010020104202521011003046014030061130304
+611403006202420040100200401004450610030460140300601303046214030065
+024200401002004010042101250404401423006014030454142304601403101210
+020040100200402224304014230060140300541423106014033012100200401002
+004021040524202200611403006014226061142300601440504010020040100201
+112142006114030060140260611443006015605040100200401002010420252101
+100304601403006113030461140300620242004010020040100445061003046014
+030060130304621403007002420040100200401004210125040440142300601403
+045414230460140314121002004010020040222430401423006014030054142310
+601403441210020040100200402104052420220061140300601422606114230060
+146050401002004010020111214200611403006014026061144300611400504010
+020040100201042025210110030460140300611303046114030063024200401002
+004010044506100304601403006013030462140304610242004010020040100421
+012504044014230060140304541423046014031412100200401002004022243040
+142300601403005414231060142310121002004010020040210405242022006114
+030060142260611423006014605040100200401002011121420061140300601402
+606114430061146050401002004010020104202521011003046014030061130304
+611403006302420040100200401004450610030460140300601303046214030464
+024200401002004010042101250404401423006014030454142304601403141210
+020040100200402224304014230060140300541423106014232412100200401002
+004021040524202200611403006014226061142300601460504010020040100201
+032364712422247125212200611403046214405103100421012344351422247107
+100304601004312223646440204425062365110502430460142310631004450610
+030460140300601303046214030060024200401002004010042101250404401423
+006014030454142304601403201210020040100200402224304014230060140300
+541423106014030412100200401002004021040524202200611403006014226061
+142300601500504010020040100201112142006114030060140260611443006014
+405040100200401002010420252101100304601403006113030461140300640242
+004010020040100445061003046014030060130304621403006302420040100200
+401004210125040440142300601403045414230460140320121002004010020040
+222430401423006014030054142310601403201210020040100200402104052420
+220061140300601422606114230060150050401002004010020111214200611403
+006014026061144300601520504010020040100201042025210110030460140300
+611303046114030064024200401002004010044506100304601403006013030462
+140300660242004010020040100421012504044014230060140304541423046014
+032012100200401002004022243040142300601403005414231060140334121002
+004010020040210405242022006114030060142260611423006015005040100200
+401002011121420061140300601402606114430060160050401002004010020104
+202521011003046014030061130304611403006502420040100200401004450610
+030460140300601303046214030071024200401002004010042101250404401423
+006014030454142304601403241210020040100200402224304014230060140300
+541423106014230012100200401002004021040524202200611403006014226061
+142300601520504010020040100201112142006114030060140260611443006114
+205040100200401002010420252101100304601403006113030461140300650242
+004010020040100445061003046014030060130304621403046202420040100200
+401004210125040440142300601403045414230460140324121002004010020040
+222430401423006014030054142310601423141210020040100200402104052420
+220061140300601422606114230060152050401002004010020111214200611403
+006014026061144300611500504010020040100201042025210110030460140300
+611303046114030065024200401002004010044506100304601403006013030462
+140304650242004010020040100421012504044014230060140304541423046014
+032412100200401002004020647516250445162524244014230061144314122062
+010420247107230445162162006114220106244475151004110521447522212050
+611403046215020111214200611403006014026061144300601400504010020040
+100201042025210110030460140300611303046114030066024200401002004010
+044506100304601403006013030462140300610242004010020040100421012504
+044014230060140304541423046014033012100200401002004022243040142300
+601403005414231060140310121002004010020040210405242022006114030060
+142260611423006015405040100200401002011121420061140300601402606114
+430060146050401002004010020104202521011003046014030061130304611403
+006602420040100200401004450610030460140300601303046214030064024200
+401002004010042101250404401423006014030454142304601403301210020040
+100200402224304014230060140300541423106014032412100200401002004021
+040524202200611403006014226061142300601540504010020040100201112142
+006114030060140260611443006015405040100200401002010420252101100304
+601403006113030461140300660242004010020040100445061003046014030060
+130304621403006702420040100200401004210125040440142300601403045414
+230460140330121002004010020040222430401423006014030054142310601403
+401210020040100200402104052420220061140300601422606114230060156050
+401002004010020111214200611403006014026061144300601620504010020040
+100201042025210110030460140300611303046114030067024200401002004010
+044506100304601403006013030462140304600242004010020040100421012504
+044014230060140304541423046014033412100200401002004022243040142300
+601403005414231060142304121002004010020040210405242022006114030060
+142260611423006015605040100200401002011121420061140300601402606114
+430061144050401002004010020104202521011003046014030061130304611403
+006702420040100200401004450610030460140300601303046214030463024200
+401002004010042101250404401423006014030454142304601403341210020040
+100200402224304014230060140300541423106014232012100200401002004021
+040524202200611403006014226061142300601560504010020040100201112142
+006114030060140260611443006115205040100200401002010420252101100304
+601403006113030461140300670242004010020040100415172345211123452505
+100304601423106402441440206475162465210123452123024304611403006010
+042101250404401422606002430461140300611004210125040440142260610243
+046114030062100421012504044014226062024304611403006310042101250404
+401422606302430461140300641004210125040440142260640243046114030065
+100421012504044014226065024304611403006610042101250404401422606602
+430461140300671004210125040440142260670243046214030060100421012504
+044014426060140050611443006014220104202521011003105414030412142310
+601403104021040524202200621303006202430462140300631004210125040440
+144260601460506114430060150201042025210110031054140320121423106014
+032440210405242022006213030065024304621403006610042101250404401442
+606015405061144300601562010420252101100310541403341214231060140340
+402104052420220062130300700243046214030071100421012504044014426060
+162050611443006114020104202521011003105414230012142310601423044021
+040524202200621303046102430462140304621004210125040440144260611440
+506114430061146201042025210110031054142314121423106014232040210405
+242022006213030464024304621403046510042101250404401442606115205061
+146300611442010420252101100314541403046202434471162344711004210125
+0404401503006014030054

Monday, March 22, 2010

Here is 99 bottles of beer in RESOL.

C 99 BOTTLES IN RESOL
001 DATA 000001
DATA 003,9876543210
DATA 004,9876543210
DATA 005,99
CALL 007,7
CALL 10002
CALL 002
STOP
002 DATA 000001
DATA 002
DATA 002,10001
DATA 001,10001
DATA 10001
CONTINUE 002
003 DATA 000001
004 DATA 000001
005 DATA 000002
C DECREMENT COUNTER
006 IF 003,0
DATA 003,9876543210
IF 003,0
DATA 004
DATA 003
DATA 005,004
DATA 005,003
DATA 005
CONTINUE 006
007 DATA 000001
CALL 100,005
CALL 008
CALL 10000,0200 0415 0406 0200 0402 0405 0405 0502
+ 0200 0415 0414 0200 0504 0408 0405
+ 0200 0507 0401 0412 0412 0212 0200
CALL 100,005
CALL 008
CALL 10000,0200 0415 0406 0200 0402 0405 0405 0502 0214 0010
CALL 002
IF 00,005
CONTINUE 007,009
CALL 10000,0504 0401 0411 0405 0200 0415 0414 0405
+ 0200 0404 0415 0507 0414 0200 0401 0414 0404
+ 0200 0500 0401 0503 0503 0200 0409 0504
+ 0200 0401 0502 0415 0505 0414 0404 0212 0200
CALL 006
CALL 100,005
CALL 008
CALL 10000,0200 0415 0406 0200 0402 0405 0405 0502
+ 0200 0415 0414 0200 0504 0408 0405
+ 0200 0507 0401 0412 0412 0214 0010 0010
CALL 002
CONTINUE 007
C BOTTLE(S)
008 CALL 10000,0200 0402 0415 0504 0504 0412 0405
IF 01,005
CONTINUE 008
CALL 10000,0503
CONTINUE 008
009 CALL 10000,0407 0415 0200 0504 0415 0200 0504 0408 0405
+ 0200 0503 0504 0415 0502 0405 0200 0401 0414 0404
+ 0200 0402 0505 0509 0200 0503 0415 0413 0405
+ 0200 0413 0415 0502 0405 0212 0200 0309 0309
+ 0200 0402 0415 0504 0504 0412 0405 0503
+ 0200 0415 0406 0200 0402 0405 0405 0502
+ 0200 0415 0414 0200 0504 0408 0405
+ 0200 0507 0401 0412 0412 0214 0010
DATA 007
CONTINUE 007
C OUTPUT PASSED IN COUNT OR "NO MORE" WHEN COUNT IS 00
100 DATA 000001
IF 100,0
CALL 101
CONTINUE 100,103
101 DATA 100
IF 100,0
CALL 10000,0414041502000413041505020405
IF 100,0
CONTINUE 100,102
CALL 104
102 DATA 100
CONTINUE 101
103 CALL 104
DATA 100
CALL 104
DATA 100
CONTINUE 100
104 IF 100,0
CALL 10000,0300
IF 100,1
CALL 10000,0301
IF 100,2
CALL 10000,0302
IF 100,3
CALL 10000,0303
IF 100,4
CALL 10000,0304
IF 100,5
CALL 10000,0305
IF 100,6
CALL 10000,0306
IF 100,7
CALL 10000,0307
IF 100,8
CALL 10000,0308
IF 100,9
CALL 10000,0309
CONTINUE 104
C THIS IS A LIBRARY THAT CONVERTS 4-BIT ITEMS ENQUEUED INTO 10000 AS 2 DIGITS
C INTO 3-BIT ITEMS IN 1 DIGIT THAT ARE AVAILABLE AT 10001.
C CALL 10000 TO PROCESS ITEMS FROM 10000 INTO 10001.
C CALL 10002 TO FLUSH THE FINAL DANGLING BITS (0-2 BITS).
C
C IF 000002 IS A DATA STATEMENT, CALLING 10000 WILL DEQUEUE FROM IT. BEST
C NOT TO HAVE 000002 AS A LABEL (WHICH WOULD REQUIRE A CONTINUATION LINE).
C
10000 DATA 000002
IF 10003,11000
CALL 10100
IF 10003,11001
CALL 10110
IF 10003,11002
CALL 10120
DATA 10003
DATA 10000
CONTINUE 10000
10001 DATA 1
C
C FLUSH THE FINAL DANGLING BITS
10002 IF 10003,11000
CONTINUE 10002
DATA 10001,10004
DATA 10004
C REINITIALIZE 10003 TO 012
IF 10003,11001
DATA 10003
DATA 10003
DATA 10003,012
CONTINUE 10002
C
C 10003 HOLDS THE NUMBER OF DANGLING BITS
10003 DATA 1,012
C 10004 HOLDS THE VALUE OF THE DANGLING BITS
10004 DATA 1
C
C NO DANGLING BITS FROM BEFORE. LEAVES 1 DANGLING BIT FOR NEXT ITEM.
10100 IF 10000,12000
DATA 10001,11000
IF 10000,12000
DATA 10004,11000
IF 10000,12001
DATA 10001,11000
IF 10000,12001
DATA 10004,11004
IF 10000,12002
DATA 10001,11001
IF 10000,12002
DATA 10004,11000
IF 10000,12003
DATA 10001,11001
IF 10000,12003
DATA 10004,11004
IF 10000,12004
DATA 10001,11002
IF 10000,12004
DATA 10004,11000
IF 10000,12005
DATA 10001,11002
IF 10000,12005
DATA 10004,11004
IF 10000,12006
DATA 10001,11003
IF 10000,12006
DATA 10004,11000
IF 10000,12007
DATA 10001,11003
IF 10000,12007
DATA 10004,11004
IF 10000,12008
DATA 10001,11004
IF 10000,12008
DATA 10004,11000
IF 10000,12009
DATA 10001,11004
IF 10000,12009
DATA 10004,11004
IF 10000,12010
DATA 10001,11005
IF 10000,12010
DATA 10004,11000
IF 10000,12011
DATA 10001,11005
IF 10000,12011
DATA 10004,11004
IF 10000,12012
DATA 10001,11006
IF 10000,12012
DATA 10004,11000
IF 10000,12013
DATA 10001,11006
IF 10000,12013
DATA 10004,11004
IF 10000,12014
DATA 10001,11007
IF 10000,12014
DATA 10004,11000
IF 10000,12015
DATA 10001,11007
IF 10000,12015
DATA 10004,11004
CONTINUE 10100
C
C 1 DANGLING BIT FROM BEFORE. LEAVES 2 DANGLING BITS FOR NEXT ITEM.
10110 IF 10004,11000
CALL 10111
IF 10004,11004
CALL 10112
DATA 10004
CONTINUE 10110
C DANGLING 0 FROM BEFORE
10111 IF 10000,12000
DATA 10001,11000
IF 10000,12000
DATA 10004,11000
IF 10000,12001
DATA 10001,11000
IF 10000,12001
DATA 10004,11002
IF 10000,12002
DATA 10001,11000
IF 10000,12002
DATA 10004,11004
IF 10000,12003
DATA 10001,11000
IF 10000,12003
DATA 10004,11006
IF 10000,12004
DATA 10001,11001
IF 10000,12004
DATA 10004,11000
IF 10000,12005
DATA 10001,11001
IF 10000,12005
DATA 10004,11002
IF 10000,12006
DATA 10001,11001
IF 10000,12006
DATA 10004,11004
IF 10000,12007
DATA 10001,11001
IF 10000,12007
DATA 10004,11006
IF 10000,12008
DATA 10001,11002
IF 10000,12008
DATA 10004,11000
IF 10000,12009
DATA 10001,11002
IF 10000,12009
DATA 10004,11002
IF 10000,12010
DATA 10001,11002
IF 10000,12010
DATA 10004,11004
IF 10000,12011
DATA 10001,11002
IF 10000,12011
DATA 10004,11006
IF 10000,12012
DATA 10001,11003
IF 10000,12012
DATA 10004,11000
IF 10000,12013
DATA 10001,11003
IF 10000,12013
DATA 10004,11002
IF 10000,12014
DATA 10001,11003
IF 10000,12014
DATA 10004,11004
IF 10000,12015
DATA 10001,11003
IF 10000,12015
DATA 10004,11006
CONTINUE 10111
C DANGLING 1 FROM BEFORE
10112 IF 10000,12000
DATA 10001,11004
IF 10000,12000
DATA 10004,11000
IF 10000,12001
DATA 10001,11004
IF 10000,12001
DATA 10004,11002
IF 10000,12002
DATA 10001,11004
IF 10000,12002
DATA 10004,11004
IF 10000,12003
DATA 10001,11004
IF 10000,12003
DATA 10004,11006
IF 10000,12004
DATA 10001,11005
IF 10000,12004
DATA 10004,11000
IF 10000,12005
DATA 10001,11005
IF 10000,12005
DATA 10004,11002
IF 10000,12006
DATA 10001,11005
IF 10000,12006
DATA 10004,11004
IF 10000,12007
DATA 10001,11005
IF 10000,12007
DATA 10004,11006
IF 10000,12008
DATA 10001,11006
IF 10000,12008
DATA 10004,11000
IF 10000,12009
DATA 10001,11006
IF 10000,12009
DATA 10004,11002
IF 10000,12010
DATA 10001,11006
IF 10000,12010
DATA 10004,11004
IF 10000,12011
DATA 10001,11006
IF 10000,12011
DATA 10004,11006
IF 10000,12012
DATA 10001,11007
IF 10000,12012
DATA 10004,11000
IF 10000,12013
DATA 10001,11007
IF 10000,12013
DATA 10004,11002
IF 10000,12014
DATA 10001,11007
IF 10000,12014
DATA 10004,11004
IF 10000,12015
DATA 10001,11007
IF 10000,12015
DATA 10004,11006
CONTINUE 10112
C
C 2 DANGLING BITS FROM BEFORE. LEAVES NO DANGLING BITS FOR NEXT ITEM.
10120 IF 10004,11000
CALL 10121
IF 10004,11002
CALL 10122
IF 10004,11004
CALL 10123
IF 10004,11006
CALL 10124
DATA 10003,13012
DATA 10004
IF 10000,12000
DATA 10001,11000
IF 10000,12001
DATA 10001,11001
IF 10000,12002
DATA 10001,11002
IF 10000,12003
DATA 10001,11003
IF 10000,12004
DATA 10001,11004
IF 10000,12005
DATA 10001,11005
IF 10000,12006
DATA 10001,11006
IF 10000,12007
DATA 10001,11007
IF 10000,12008
DATA 10001,11000
IF 10000,12009
DATA 10001,11001
IF 10000,12010
DATA 10001,11002
IF 10000,12011
DATA 10001,11003
IF 10000,12012
DATA 10001,11004
IF 10000,12013
DATA 10001,11005
IF 10000,12014
DATA 10001,11006
IF 10000,12015
DATA 10001,11007
CONTINUE 10120
C DANGLING 00 FROM BEFORE
10121 IF 10000,12000
DATA 10001,11000
IF 10000,12001
DATA 10001,11000
IF 10000,12002
DATA 10001,11000
IF 10000,12003
DATA 10001,11000
IF 10000,12004
DATA 10001,11000
IF 10000,12005
DATA 10001,11000
IF 10000,12006
DATA 10001,11000
IF 10000,12007
DATA 10001,11000
IF 10000,12008
DATA 10001,11001
IF 10000,12009
DATA 10001,11001
IF 10000,12010
DATA 10001,11001
IF 10000,12011
DATA 10001,11001
IF 10000,12012
DATA 10001,11001
IF 10000,12013
DATA 10001,11001
IF 10000,12014
DATA 10001,11001
IF 10000,12015
DATA 10001,11001
CONTINUE 10121
C DANGLING 01 FROM BEFORE
10122 IF 10000,12000
DATA 10001,11002
IF 10000,12001
DATA 10001,11002
IF 10000,12002
DATA 10001,11002
IF 10000,12003
DATA 10001,11002
IF 10000,12004
DATA 10001,11002
IF 10000,12005
DATA 10001,11002
IF 10000,12006
DATA 10001,11002
IF 10000,12007
DATA 10001,11002
IF 10000,12008
DATA 10001,11003
IF 10000,12009
DATA 10001,11003
IF 10000,12010
DATA 10001,11003
IF 10000,12011
DATA 10001,11003
IF 10000,12012
DATA 10001,11003
IF 10000,12013
DATA 10001,11003
IF 10000,12014
DATA 10001,11003
IF 10000,12015
DATA 10001,11003
CONTINUE 10122
C DANGLING 10 FROM BEFORE
10123 IF 10000,12000
DATA 10001,11004
IF 10000,12001
DATA 10001,11004
IF 10000,12002
DATA 10001,11004
IF 10000,12003
DATA 10001,11004
IF 10000,12004
DATA 10001,11004
IF 10000,12005
DATA 10001,11004
IF 10000,12006
DATA 10001,11004
IF 10000,12007
DATA 10001,11004
IF 10000,12008
DATA 10001,11005
IF 10000,12009
DATA 10001,11005
IF 10000,12010
DATA 10001,11005
IF 10000,12011
DATA 10001,11005
IF 10000,12012
DATA 10001,11005
IF 10000,12013
DATA 10001,11005
IF 10000,12014
DATA 10001,11005
IF 10000,12015
DATA 10001,11005
CONTINUE 10123
C DANGLING 11 FROM BEFORE
10124 IF 10000,12000
DATA 10001,11006
IF 10000,12001
DATA 10001,11006
IF 10000,12002
DATA 10001,11006
IF 10000,12003
DATA 10001,11006
IF 10000,12004
DATA 10001,11006
IF 10000,12005
DATA 10001,11006
IF 10000,12006
DATA 10001,11006
IF 10000,12007
DATA 10001,11006
IF 10000,12008
DATA 10001,11007
IF 10000,12009
DATA 10001,11007
IF 10000,12010
DATA 10001,11007
IF 10000,12011
DATA 10001,11007
IF 10000,12012
DATA 10001,11007
IF 10000,12013
DATA 10001,11007
IF 10000,12014
DATA 10001,11007
IF 10000,12015
DATA 10001,11007
CONTINUE 10124
C
C CONSTANTS
11000 DATA 1,0
11001 DATA 1,1
11002 DATA 1,2
11003 DATA 1,3
11004 DATA 1,4
11005 DATA 1,5
11006 DATA 1,6
11007 DATA 1,7
12000 DATA 2,00
12001 DATA 2,01
12002 DATA 2,02
12003 DATA 2,03
12004 DATA 2,04
12005 DATA 2,05
12006 DATA 2,06
12007 DATA 2,07
12008 DATA 2,08
12009 DATA 2,09
12010 DATA 2,10
12011 DATA 2,11
12012 DATA 2,12
12013 DATA 2,13
12014 DATA 2,14
12015 DATA 2,15
13012 DATA 3,012

Monday, March 15, 2010

After getting reacquainted with Haskell, I really like using it. However, using lots of higher-order functions and operators makes for dense APL-like code that is inaccessible to those unfamiliar with those functions and operators. And, parser combinators introduce very expressive and extensible ways to create parsers, but would also look foreign to the uninitiated. But these operators and functions also can be used to make very elegant and maintainable code.

For example, I'm writing code to deal with JVM class files. To write to a class file, I want to convert various things to a list of bytes, so I made a typeclass for that:

class ToBytes a where
toBytes :: a -> [Word8]

Then, since many objects, when converted to a list of bytes, are just the concatenation of the conversion of component objects, I defined

concatAccessors :: [a -> [b]] -> a -> [b]
concatAccessors = flip (.) (flip ($)) . flip concatMap

which is an example of dense APL-like code, using the (.) and ($) operators and the flip and concatMap higher-order functions. However, it enables this:

instance ToBytes JVMClass where
toBytes = concatAccessors [
toBytes . jvmClassMagic,
toBytes . jvmClassMinorVersion,
toBytes . jvmClassMajorVersion,
toBytes . jvmClassConstantPool,
toBytes . jvmClassAccessFlags,
toBytes . jvmClassThisClass,
toBytes . jvmClassSuperClass,
toBytes . jvmClassInterfaces,
toBytes . jvmClassFields,
toBytes . jvmClassMethods,
toBytes . jvmClassAttributes
]

For most of the cases, having the ToBytes type class doesn't buy me that much. It saves having to have separate names for jvmClassToBytes, word16ToBytes, word32ToBytes, etc, but they still have to be defined. However, when there are lists of items in the class file format, it is preceded with a 16 bit count, so I can define

instance ToBytes a => ToBytes [a] where
toBytes l = toBytes (fromIntegral (length l) :: Word16) ++ concatMap toBytes l

so the constant pool (with a hack for the off by 1 length and the double-sized long and double constants), and the lists of interfaces, fields, methods, and attributes can be taken care of by defining toBytes for single items.

For reading class files, I learned how to make a state-transformer monad, which looks like this

newtype ST st a = ST (st -> (a,st))

instance Monad (ST st) where
p >>= q = ST (uncurry (s . q) . s p) where s (ST t) = t
return = ST . (,)

runST :: ST st a -> st -> a
runST (ST t) = fst . t

There are the uncurry higher-order function and the (.) operator making things hard to understand for those unfamiliar with them, not to mention the odd looking (,) constructor. However, it enables code like this:

readJVMClass :: ST State JVMClass
readJVMClass = do
magic <- readWord32
minorVersion <- readWord16
majorVersion <- readWord16
constantPool <- readConstantPool
accessFlags <- readWord16
thisClass <- readWord16
superClass <- readWord16
interfaces <- readList readWord16
fields <- readList readField
methods <- readList readMethod
attributes <- readList readAttribute
return (JVMClass magic minorVersion majorVersion constantPool accessFlags
thisClass superClass interfaces fields methods attributes)

which is very maintainable.

Using Functor and Applicative

instance Functor (ST st) where
fmap f p = do { a <- p; return (f a) }

instance Applicative (ST st) where
pure = return
p <*> q = do { f <- p; a <- q; return (f a) }

it could be written more concisely, but with more weird operators:

readJVMClass = JVMClass <$> readWord32
<*> readWord16
<*> readWord16
<*> readConstantPool
<*> readWord16
<*> readWord16
<*> readWord16
<*> readList readWord16
<*> readList readField
<*> readList readMethod
<*> readList readAttribute

readJVMClass (readWord32, readWord16, ...) doesn't return a JVMClass (Word32, Word16, ...), it returns a state transformer, which is a function that takes a state, and returns an updated state and a JVMClass (Word32, Word16, ...). readJVMClass just builds a state transformer that chains other state transformers and extracts the values that they return. To actually do the reading and building, one must use runST.

Monday, March 8, 2010

There was some feature that, due to changes in an external service, stopped working. The trunk was fixed to work with the new version of the external service, but the release branch was not. The bug report classified it as a regression, but it wasn't a regression, as the feature had stopped working in the same manner in production. It was decided that it was too risky to copy the fix from the trunk to the release branch.

Now, this new release also included the launch of a new virtual host, where having the non-working feature was not an option, so it was decided that the feature had to be disabled for that virtual host, so an ugly hack got put in to disable that feature for one set of use cases. Then, I got called in to review the hack and was told that it needed to be extended to some other use cases. It turned out that I had added a general mechanism to do per-virtual host configuration 8 or 9 months earlier for another feature, so the ugly hack was reverted, and per-virtual host configuration was changed to disable that feature for all the use cases on that virtual host.

Monday, March 1, 2010

I got a 3am call because of some problem when a new version went out to production. It turned out to be some code using an external hostname that was invisible to the internal host. I wasn't involved in figuring out the problem, because I was looking at the pieces that I had worked on. When it was figured out, I went back to sleep. These problems keep turning up because there are no distinct internal and external hostnames in the testing and development environments, and anyone new to the project hasn't gotten lots of these late-night calls.