<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1029341293641516198</id><updated>2012-02-16T13:11:02.029-08:00</updated><title type='text'>I write the code</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default?start-index=101&amp;max-results=100'/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>155</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-636365530050518114</id><published>2011-05-23T00:00:00.000-07:00</published><updated>2011-05-23T00:00:01.787-07:00</updated><title type='text'></title><content type='html'>I was writing some Haskell code where I was constructing a value with lots of record fields, but only cared about one of them initially.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;data Type = Type { field1 :: Type1, field2 :: Type2 }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But, omitting the irrelevant fields from the initializer causes a big  "Fields not initialised" warning.&lt;br /&gt;&lt;br /&gt;So, I figured that, instead of writing out&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Type { field1 = value, field2 = undefined }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which was verbose, or&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Type { field1 = value }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which resulted in the big warning, I could use&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;undefined { field1 = value }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which did eliminate the warning.&lt;br /&gt;&lt;br /&gt;However,&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;field1 (undefined { field1 = value })&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;resulted in an exception.  I had expected it to be equivalent to&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;field1 (Type { field1 = value, field2 = field2 undefined })&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;but it's not.  Since types can have multiple constructors, it's actually equivalent to&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;field1 (case undefined of { Type { field2 = field2 } -&amp;gt; Type { field1 = value, field2 = field2 })&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;according to section 3.16.3 in the Haskell report.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-636365530050518114?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/636365530050518114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/05/i-was-writing-some-haskell-code-where-i.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/636365530050518114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/636365530050518114'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/05/i-was-writing-some-haskell-code-where-i.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-1769623924454195038</id><published>2011-05-09T00:00:00.000-07:00</published><updated>2011-05-09T00:00:10.687-07:00</updated><title type='text'></title><content type='html'>While trying to write concurrent code that forks off threads that sleep before doing some delayed actions using &lt;a href="http://www.haskell.org/ghc"&gt;GHCi, version 6.10.4&lt;/a&gt;, which is a pretty old version, I found some strange behavior.  I used &lt;code&gt;map (flip addUTCTime time) [1..5]&lt;/code&gt; to generate the times that the delayed actions should be performed, and the interpreter would lock up.  When I changed it to &lt;code&gt;map (flip addUTCTime time) [1,2,3,4,5]&lt;/code&gt;, everything worked as expected.  Maybe there is something tricky in the implementation of &lt;code&gt;enumFromTo :: NominalDiffTime -&amp;gt; NominalDiffTime -&amp;gt; [NominalDiffTime]&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-1769623924454195038?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/1769623924454195038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/05/while-trying-to-write-concurrent-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1769623924454195038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1769623924454195038'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/05/while-trying-to-write-concurrent-code.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-5516240332905427960</id><published>2011-04-25T00:00:00.000-07:00</published><updated>2011-04-25T00:00:07.792-07:00</updated><title type='text'></title><content type='html'>I started using &lt;code&gt;Control.Concurrent&lt;/code&gt; to write concurrent code in Haskell.  It's easier than Java's concurrency model, since values are immutable in Haskell, while one has to worry about values being changed by other threads in Java, which means having to use locks in the right places, and knowing how to use the java.util.concurrent classes.&lt;br /&gt;&lt;br /&gt;Of course, it's still possible to deadlock in Haskell, such as with &lt;code&gt;do { a &lt;- takeMVar ma; b &lt;- readMVar mb; putMVar ma a }&lt;/code&gt; and &lt;code&gt;do { b &lt;- takeMVar mb; a &lt;- readMVar ma; putMVar mb b }&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Also, there is no getting around dealing with external concurrency issues, such as with databases.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-5516240332905427960?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/5516240332905427960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/04/i-started-using-control.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/5516240332905427960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/5516240332905427960'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/04/i-started-using-control.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-3922354023551051618</id><published>2011-04-11T00:00:00.000-07:00</published><updated>2011-04-11T00:00:09.740-07:00</updated><title type='text'></title><content type='html'>Thinking about real numbers in the &lt;a href="/2009/06/01-programming-language.html"&gt;01_ programming language&lt;/a&gt;, the fractional part can be represented as big endian base 1/2.  (Or is it little endian?  Bits to the left represent larger numbers, but smaller powers of 1/2.)  Infinite lists of bits can represent numbers that are &amp;ge; 0 and &amp;le; 1.&lt;br /&gt;&lt;br /&gt;Addition of fractional numbers can be defined as&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;+/fractional 0a 0b = +/fractional/carry a b 0_ 1_ +/fractional a b.&lt;br /&gt;+/fractional 1a 0b = +/fractional/carry a b 1_ 0_ +/fractional a b.&lt;br /&gt;+/fractional 0a 1b = +/fractional/carry a b 1_ 0_ +/fractional a b.&lt;br /&gt;+/fractional 1a 1b = +/fractional/carry a b 0_ 1_ +/fractional a b.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;where evaluating the carry of fractional addition is&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;+/fractional/carry 0a 0b carry-zero carry-one = carry-zero.&lt;br /&gt;+/fractional/carry 1a 0b carry-zero carry-one = +/fractional/carry a b carry-zero carry-one.&lt;br /&gt;+/fractional/carry 0a 1b carry-zero carry-one = +/fractional/carry a b carry-zero carry-one.&lt;br /&gt;+/fractional/carry 1a 1b carry-zero carry-one = carry-one.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And the subtraction of fractional numbers is&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-/fractional 0a 0b = -/fractional/borrow a b 0_ 1_ -/fractional a b.&lt;br /&gt;-/fractional 1a 0b = -/fractional/borrow a b 1_ 0_ -/fractional a b.&lt;br /&gt;-/fractional 0a 1b = -/fractional/borrow a b 1_ 0_ -/fractional a b.&lt;br /&gt;-/fractional 1a 1b = -/fractional/borrow a b 0_ 1_ -/fractional a b.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;where evaluating the borrow of fractional subtraction is&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-/fractional/borrow 0a 0b borrow-zero borrow-one = -/fractional/borrow a b borrow-zero borrow-one.&lt;br /&gt;-/fractional/borrow 1a 0b borrow-zero borrow-one = borrow-zero.&lt;br /&gt;-/fractional/borrow 0a 1b borrow-zero borrow-one = borrow-one.&lt;br /&gt;-/fractional/borrow 1a 1b borrow-zero borrow-one = -/fractional/borrow a b borrow-zero borrow-one.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Unlike the addition and subtraction of integers, these operations, in general, require infinite time and memory to calculate a finite number of bits, due to the carry and borrow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-3922354023551051618?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/3922354023551051618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/04/thinking-about-real-numbers-in-01.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3922354023551051618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3922354023551051618'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/04/thinking-about-real-numbers-in-01.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-6920831705029635941</id><published>2011-03-28T00:00:00.000-07:00</published><updated>2011-03-28T00:00:06.339-07:00</updated><title type='text'></title><content type='html'>Thinking about numbers in the &lt;a href="/2009/06/01-programming-language.html"&gt;01_ programming language&lt;/a&gt;, the natural way to represent integers would be to use little-endian base 2.  To further simplify things, consider only infinite lists of bits.  So the important numbers are&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;zero = 0 zero.&lt;br /&gt;one = 1 zero.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Negative numbers can also be represented&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-one = 1 -one.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Integer addition can be defined as&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;+/integer 0a 0b = 0 +/integer a b.&lt;br /&gt;+/integer 1a 0b = 1 +/integer a b.&lt;br /&gt;+/integer 0a 1b = 1 +/integer a b.&lt;br /&gt;+/integer 1a 1b = 0 +/integer/carry a b.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;where integer addition with carry is&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;+/integer/carry 0a 0b = 1 +/integer a b.&lt;br /&gt;+/integer/carry 1a 0b = 0 +/integer/carry a b.&lt;br /&gt;+/integer/carry 0a 1b = 0 +/integer/carry a b.&lt;br /&gt;+/integer/carry 1a 1b = 1 +/integer/carry a b.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And integer subtraction is&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-/integer 0a 0b = 0 -/integer a b.&lt;br /&gt;-/integer 1a 0b = 1 -/integer a b.&lt;br /&gt;-/integer 0a 1b = 1 -/integer/borrow a b.&lt;br /&gt;-/integer 1a 1b = 0 -/integer a b.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;where integer subtraction with borrow is&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-/integer/borrow 0a 0b = 1 -/integer/borrow a b.&lt;br /&gt;-/integer/borrow 1a 0b = 0 -/integer a b.&lt;br /&gt;-/integer/borrow 0a 1b = 0 -/integer/borrow a b.&lt;br /&gt;-/integer/borrow 1a 1b = 1 -/integer/borrow a b.&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-6920831705029635941?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/6920831705029635941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/03/thinking-about-numbers-in-01.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6920831705029635941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6920831705029635941'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/03/thinking-about-numbers-in-01.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-7456687551420641384</id><published>2011-03-14T00:00:00.000-07:00</published><updated>2011-03-14T00:00:28.448-07:00</updated><title type='text'></title><content type='html'>For work, some of the code is in JSTL (JavaServer Pages Standard Template Library) EL (Expression Language).  JSTL EL is weakly typed and dynamically typed.  There is no compile-time checking.&lt;br /&gt;&lt;br /&gt;One day, a coworker sent me a message saying some stuff stopped working after merging in some of my changes.  So I tried running it and it didn't work.  I also added logging to the code I changed, which was all Java, and it was working fine.  I then tracked it down to some JSTL (untouched by me):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;c:set var="flag" value="{flag1 || flag2}"/&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;c:if test="${flag}"&amp;gt;&lt;br /&gt;... stuff that failed to appear ...&lt;br /&gt;&amp;lt;/c:if&amp;gt;&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;The first line should have been&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;c:set var="flag" value="${flag1 || flag2}"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is the type of stupid mistake that compile-time checking, especially with static typing, can catch.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-7456687551420641384?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/7456687551420641384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/03/for-work-some-of-code-is-in-jstl.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7456687551420641384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7456687551420641384'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/03/for-work-some-of-code-is-in-jstl.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-4672655148391936323</id><published>2011-02-28T00:00:00.000-08:00</published><updated>2011-02-28T00:00:07.222-08:00</updated><title type='text'></title><content type='html'>I wrote a compiler for &lt;a href="/2009/06/01-programming-language.html"&gt;01_&lt;/a&gt; to &lt;a href="http://llvm.org/"&gt;LLVM&lt;/a&gt; (Low Level Virtual Machine) in a week of weekends and evenings.  LLVM's static type-checking caught numerous silly mistakes.  However, I got bit twice because LLVM does not warn, at least with the default option, when the calling convention declaration of the caller and callee do not match.  (I use fastcc because tail-call elimination is important for 01_ programs, and failed to specify it in the caller those two times.)  This seems like something that could be checked by the computer and reminds me why I prefer using statically typed programming languages over dynamically typed programming languages.&lt;br /&gt;&lt;br /&gt;I wrote the parser in one evening, which I had done before, so it was mostly a matter of getting reacquainted with the Parsec parsing library.&lt;br /&gt;&lt;br /&gt;I spent another evening and a weekend learning the LLVM assembly language and writing the runtime library.&lt;br /&gt;&lt;br /&gt;I spent another couple of evenings writing the code generator.&lt;br /&gt;&lt;br /&gt;I spent the last evening chasing down memory leaks in the generated code.&lt;br /&gt;&lt;br /&gt;The code is available at &lt;a href="https://github.com/qpliu/esolang/tree/master/01_/hs/compiler"&gt;github.com&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-4672655148391936323?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/4672655148391936323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/02/i-wrote-compiler-for-01-to-llvm-low.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/4672655148391936323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/4672655148391936323'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/02/i-wrote-compiler-for-01-to-llvm-low.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-8116667956859245543</id><published>2011-02-14T00:00:00.000-08:00</published><updated>2011-02-14T00:00:21.918-08:00</updated><title type='text'></title><content type='html'>I had been thinking about compiling &lt;a href="/2009/06/01-programming-language.html"&gt;01_&lt;/a&gt; to &lt;a href="http://llvm.org/"&gt;LLVM&lt;/a&gt; for a while, and finally decided to get started on it by playing around with LLVM assembly language.  One thing I like about LLVM assembly language is the static type checking.  Anyhow, I started writing a runtime library for 01_.  The only data type in 01_ is a lazy list of bits.  The data type does not permit circular references, so I'll use reference counting garbage collection.&lt;br /&gt;&lt;br /&gt;Here's my first stab at the data type for 01_ values:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;%val = type { i32, i1, %val*, { i1, %.val* } (i8*)*, void (i8*)*, i8* }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which, in a C-like syntax would be:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;struct val {&lt;br /&gt;    int refcount;&lt;br /&gt;    bool bit;&lt;br /&gt;    struct val *next;&lt;br /&gt;    struct { bool bit, struct val *next } (void*) *eval;&lt;br /&gt;    void (void *) *free_env;&lt;br /&gt;    void *env;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;where bit and next are undefined and eval is non-null for unevaluated promises, and bit is undefined and next is null and eval is null for values evaluating to nil, and bit contains the bit value and next points to the next value and eval is null for non-nil values.  That's a pretty large data structure for a single element of a bit list.  I could shrink it by the size of a pointer by using the same location for next and env and casting, as env and free_env are never valid at the same time as next and bit.  I won't do that, though, because it would make the code less clear, and having more understandable code is more important to me in this project.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-8116667956859245543?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/8116667956859245543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/02/i-had-been-thinking-about-compiling-01.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8116667956859245543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8116667956859245543'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/02/i-had-been-thinking-about-compiling-01.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-2575880548388081848</id><published>2011-01-31T00:00:00.000-08:00</published><updated>2011-01-31T00:00:11.823-08:00</updated><title type='text'></title><content type='html'>I've integrated purchasing with Facebook Credits into a Facebook application.  In the end, the API was good, but the documentation was terrible, making it hard to get started.  To start with, I needed to handle a callback from Facebook, and the documentation said&lt;br /&gt;&lt;blockquote&gt;There are two callbacks Facebook makes on the application back end. The application needs to verify the fb_sig parameter to make sure that the request is coming from facebook.&lt;/blockquote&gt;&lt;br /&gt;I then had to guess and use trial-and-error to get it to work.  What the documentation should have said, but didn't say was&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The callback is an HTTP POST.&lt;/li&gt;&lt;li&gt;The content-type of the posted content is &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The two callbacks are indicated by the &lt;code&gt;method&lt;/code&gt; parameter.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;fb_sig&lt;/code&gt; parameter only needs to be verified if the application does not have the OAuth 2.0 for Canvas setting enabled.  If that setting is enabled, the &lt;code&gt;fb_sig&lt;/code&gt; parameter is not sent, and all the parameters are in the &lt;code&gt;signed_request&lt;/code&gt;, which includes a signature that needs to be verified.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;order_details&lt;/code&gt; parameter is a string containing the original JSON, which means it needs to be double parsed.&lt;/li&gt;&lt;li&gt;They provide an example for the response to the &lt;code&gt;payments_get_items&lt;/code&gt; callback, but not for the &lt;code&gt;payments_status_update&lt;/code&gt; callback.  Following the given example for the &lt;code&gt;payments_status_update&lt;/code&gt; response results in an unhelpful error message to the user, with no feedback pointing to the problem.  As the documentation was unhelpful, and the Facebook developer forums had a few posts from someone facing the same problem with no response, I resorted to trial-and-error.  (I'm not creating yet another account and password just to post to that forum.)  The problem was that the &lt;code&gt;content&lt;/code&gt; field in the &lt;code&gt;payments_get_items&lt;/code&gt; response is supposed to be an array, but it is supposed to be a single item in the &lt;code&gt;payments_status_update&lt;/code&gt; response.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-2575880548388081848?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/2575880548388081848/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/01/ive-integrated-purchasing-with-facebook.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2575880548388081848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2575880548388081848'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/01/ive-integrated-purchasing-with-facebook.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-1744071716833996611</id><published>2011-01-24T00:00:00.000-08:00</published><updated>2011-01-24T00:00:17.924-08:00</updated><title type='text'></title><content type='html'>I've said that I've found the Python programming language uncompelling.  As a language, my impression is that it's a better language than perl, but I still use perl from time to time, but I don't use Python.  The main way I use perl is from the command line to run one-off scripts.  The one thing I knew about Python from the early 1990s when I first heard about it, until 2009, when I decided to try using it, was that indentation was syntactically significant, which means you can't write one-liners (even though the one line could contain 500 or more characters) like you can with braces and semicolons.  &lt;code&gt;perl -e 'while (&amp;lt;&amp;gt;) { ... }'&lt;/code&gt; is very convenient when trying to do something that would be too complicated when using pure shell constructs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-1744071716833996611?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/1744071716833996611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/01/ive-said-that-ive-found-python.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1744071716833996611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1744071716833996611'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/01/ive-said-that-ive-found-python.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-1030644111062079</id><published>2011-01-17T00:00:00.000-08:00</published><updated>2011-01-17T00:00:03.790-08:00</updated><title type='text'></title><content type='html'>I found out that in Tomcat 6, HttpServletRequest.getRequestURL() omits the ";jsessionid=[sessionid]", if present, while Tomcat 7 returns it.  In either case, HttpServletResponse.encodeRedirectURL() adds it in or replaces it with the actual session id when the client has cookies disabled.  However, what I needed was to have the ";jsessionid=[requested sessionid]", and not the actual session id, because I needed to reconstruct the URL that was actually sent for the redirect_uri parameter when obtaining an OAuth 2.0 access token.&lt;br /&gt;&lt;br /&gt;What had happened was that when multiple hosts were added to the load balancer, clients with cookies disabled would get authentication failures.  Since this was a new service in private beta, the immediate fix was to have a single host in the load balancer.  I then would add a second host to the load balancer, do a quick test, then remove the second host from the load balancer, and then look at the logs to see what was going on.  I had originally constructed the redirect_uri parameter using HttpServletResponse.encodeRedirectURL() on the results of HttpServletRequest.getRequestURL() and HttpServletRequest.getQueryString().  It worked fine with clients that had cookies enabled, because the session id wouldn't be in the URL, and the load balancer used cookies for host stickiness.  However, for clients with disabled cookies, the load balancer would bounce the client between hosts for subsequent requests, and since sessions weren't really being shared between hosts, so when a client request gets sent to a different host, it gets a new session.  (I did have a scheme to recover a very small set of essential session data through memcached, but I didn't think that saving redirect_uri in it was necessary, since it ought to be available when the client is retrieving that exact URL.  I also should have a scheme to make sure the session ids from one host never collide with session ids from another host by prepending the hostname to the session id.)&lt;br /&gt;&lt;br /&gt;After I figured out what was happening, I removed the HttpServletResponse.encodeRedirectURL() call in the construction of the redirect_uri parameter.  It seemed fine to me, because I was using Tomcat 7.  However, once it was running on other systems, there immediate failures for clients with disabled cookies.  From the logs, I could tell that HttpServletRequest.getRequestURL() was omitting the ";jsessionid=[session id]", so I theorized that it was because of differences between Tomcat 6 and Tomcat 7, and quickly confirmed it by running Tomcat 6 myself.&lt;br /&gt;&lt;br /&gt;I finally settled on an ugly hack, where if HttpServletRequest.isRequestedSessionIdFromURL() and if ":jsessionid=" were not in HttpServletRequest.getRequestURL(), I would add ";jsessionid=" + HttpServletRequest.getRequestedSessionId(), which would then work on Tomcat 6 and Tomcat 7.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-1030644111062079?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/1030644111062079/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/01/i-found-out-that-in-tomcat-6.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1030644111062079'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1030644111062079'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/01/i-found-out-that-in-tomcat-6.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-6188309756415231321</id><published>2011-01-10T00:00:00.000-08:00</published><updated>2011-01-10T00:00:07.728-08:00</updated><title type='text'></title><content type='html'>When doing some shell scripting for build and deploy processes, I ran into something I found strange and confusing.  I had a loop&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;while read host; do ssh -i id $host command; done &amp;lt; hosts&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;However, it only executed the remote command on the first host, which was odd.  I threw in some echos to see if something strange was happening, but it only confirmed that the loop only went through one iteration.  Then I changed ssh to echo, and the loop iterated through all the hosts.  Finally, I figured that ssh was slurping up stdin for some reason, causing the loop to end, and fixed the problem with&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;while read host; do ssh -n -i id $host command; done &amp;lt; hosts&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-6188309756415231321?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/6188309756415231321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/01/when-doing-some-shell-scripting-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6188309756415231321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6188309756415231321'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/01/when-doing-some-shell-scripting-for.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-1509407632858103083</id><published>2011-01-03T00:00:00.000-08:00</published><updated>2011-01-03T00:00:06.233-08:00</updated><title type='text'></title><content type='html'>I created a simple web application and put it up on Amazon Web Services for about a week.  The cost for a single instance and a single load balancer was around $21, including a few cents for storage and traffic.  It would be about $82 a month.  So I ported it to Google App Engine, where a low-traffic web application could be hosted for free.  It took about a day.  I replaced the storage layer that used Amazon S3 with one that used JDO.  I replaced the memcached layer using the net.spy.memcached client with one using the JCache (JSR107) API.  Those were straightforward and most of the rest of the code didn't need any changes.  I also added the configuration files appengine-web.xml and jdoconfig.xml.&lt;br /&gt;&lt;br /&gt;I ran into a few snags with the appengine servlet container, some of which might have been due to strange interactions with Google Guice, but that's just speculation without any real investigation.&lt;br /&gt;&lt;br /&gt;The first one is probably a bug in the appengine (or jetty) implementation of &lt;a href="http://download.oracle.com/javaee/5/api/javax/servlet/http/HttpServletResponse.html#encodeRedirectURL(java.lang.String)"&gt;HttpServletResponse.encodeRedirectURL()&lt;/a&gt;.  It erroneously added ;jsessionid=sessionid to external URLs.  I worked around that by not calling encodeRedirectURL() for external URLs, even though the javadoc says "All URLs sent to the HttpServletResponse.sendRedirect method should be run through this method."&lt;br /&gt;&lt;br /&gt;The next one seemed like some weird difference in implementations.  I used guice-servlet to configure servlet filters on /index.jsp, but they weren't being invoked for /, while the filters were being invoked under Tomcat and Glassfish.  I worked around that by changing &lt;code&gt;filter("/index.jsp").through(MyFilter.class)&lt;/code&gt; to &lt;code&gt;filter("/","/index.jsp").through(MyFilter.class)&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;The last one was the weirdest, and has to be some kind of bug in either appengine, jetty, or guice.  Once I got the filters passing the request for / through, instead of serving up /index.jsp, the service returned a redirect to //, which turned into a redirect to ///, etc, until the browser stopped due to too many redirects.  I worked around that by kludging in a special servlet for /:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    @Singleton&lt;br /&gt;    public static class RedirectToIndexJSP extends javax.servlet.http.HttpServlet {&lt;br /&gt;        private static final long serialVersionUID = 0L;&lt;br /&gt;        @Override&lt;br /&gt;        protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException {&lt;br /&gt;            request.getRequestDispatcher("/index.jsp").forward(request, response);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;After that, it all worked.  Compared to Amazon, the service on Google App Engine is a lot slower for the first request, as this is a very low-traffic application, so it's pretty much never running, and a new virtual machine starts up when a request does come in, which seems to take around 10 seconds.  Subsequent requests are reasonable, though still slower than Amazon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-1509407632858103083?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/1509407632858103083/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2011/01/i-created-simple-web-application-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1509407632858103083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1509407632858103083'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2011/01/i-created-simple-web-application-and.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-3439201449705828310</id><published>2010-12-27T00:00:00.000-08:00</published><updated>2010-12-27T00:00:00.386-08:00</updated><title type='text'></title><content type='html'>In order to access a &lt;a href="http://www.garmin.com/"&gt;Garmin&lt;/a&gt; device from Javascript in a web page, the &lt;a href="http://www.prototypejs.org/"&gt;Prototype&lt;/a&gt; framework needs to be loaded.  The bad thing about Prototype is that messes other things up.  One nice thing about &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; is that it is nonintrusive, defining only one global symbol.  Prototype, on the other hand screws with basic Javascript datatypes.&lt;br /&gt;&lt;br /&gt;The first thing that I had to deal with after loading Prototype was that I could no longer use &lt;code&gt;for (i in array) { ... }&lt;/code&gt;, to iterate through array elements without getting a bunch of extra junk.  So I rewrote my for loops to go from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;array.length - 1&lt;/code&gt; instead.&lt;br /&gt;&lt;br /&gt;The next thing really confused me for hours.  I wanted to encode a Javascript data structure as JSON, and &lt;code&gt;JSON.stringify([])&lt;/code&gt; would inexplicably result in &lt;code&gt;"\"[]\""&lt;/code&gt;.  But if I used the browser's Javascript console, &lt;code&gt;JSON.stringify([])&lt;/code&gt; would correctly result in &lt;code&gt;"[]"&lt;/code&gt;.  Finally, I came across a web page that identified Prototype as causing this problem by setting &lt;code&gt;Array.prototype.toJSON&lt;/code&gt;, among other things, which also explained to me why Prototype was screwing up my for loops iterating through arrays.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-3439201449705828310?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/3439201449705828310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/12/in-order-to-access-garmin-device-from.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3439201449705828310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3439201449705828310'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/12/in-order-to-access-garmin-device-from.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-5122521994154895317</id><published>2010-12-20T00:00:00.000-08:00</published><updated>2010-12-20T00:00:11.520-08:00</updated><title type='text'></title><content type='html'>When building a war file with ant, I found it convenient to include multiple &amp;lt;webinf/&amp;gt; elements in the war task when some of the WEB-INF files were generated, so that the source files and the generated files could be in separate directory trees.  However, if there were entries under WEB-INF that were duplicated between the directory trees, one of them would always cause ant to find the war file out of date and rebuild it.  It's not that I had any duplicated regular files, but I did have duplicated subdirectories, which had different timestamps.  I had been puzzled by why ant was always rebuilding the war file, even if nothing had changed, before looking into it.  I finally changed the war task to have a single &amp;lt;webinf/&amp;gt; element pointing at the generated files, and added a task that copies the source files into the directory tree of the generated files.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-5122521994154895317?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/5122521994154895317/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/12/when-building-war-file-with-ant-i-found.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/5122521994154895317'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/5122521994154895317'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/12/when-building-war-file-with-ant-i-found.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-1407331068422663011</id><published>2010-12-13T00:00:00.000-08:00</published><updated>2010-12-13T00:00:04.872-08:00</updated><title type='text'></title><content type='html'>Facebook authorization has some weirdness that I could only deal with with an ugly workaround.  My understanding of OAuth is that I redirect the user to a Facebook URL.  Then, Facebook sends the user back to me with a code that I exchange for an access token with Facebook.  This works fine if the user has already authorized my application: the user gets redirected to Facebook, and then redirected back to me without a hitch.&lt;br /&gt;&lt;br /&gt;However, if Facebook need the user to authorize my application, then there is a problem.  My application runs in an iframe in a Facebook page.  However, if I redirect the user to Facebook, which shows the user the authorization page, Facebook detects that it's in an iframe and grays out the page.  If the user tries to interact with it, the user gets sent to the page out of the iframe.  Once the user authorizes my application, the user gets sent back to me, but not in the iframe.  Fortunately, when the user comes to my application, Facebook passes a flag to me that says whether the user has already authorized my application.  So if the user has already authorized my application, I redirect to Facebook and things work fine.  If the user has not, then I show the user a page that has some javascript that sends the user to Facebook out of the iframe, and when the user comes back from Facebook, I redirect the user to the Facebook page that frames my application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-1407331068422663011?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/1407331068422663011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/12/facebook-authorization-has-some.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1407331068422663011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1407331068422663011'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/12/facebook-authorization-has-some.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-57518448713048199</id><published>2010-12-06T00:00:00.000-08:00</published><updated>2010-12-06T00:00:05.063-08:00</updated><title type='text'></title><content type='html'>I have an ant target that runs some scripts on some Amazon EC2 instances.  So, I first generate a file with a list the hostnames of the running instances.  Then, ant runs a shell command that iterates over the hostnames and runs ssh to each with a command.  Since I didn't want to run the command as root, the command was &lt;code&gt;su -c "\"&lt;i&gt;command with some parameters&lt;/i&gt;\"" &lt;i&gt;username&lt;/i&gt;&lt;/code&gt;, which worked fine for me.  However, on cygwin on Microsoft Windows, the nested quoting didn't work, so that su was trying to set the user to the first command parameter rather than the username I specified.  None of the variations of single and double quotes and backslash quoting the space characters worked.&lt;br /&gt;&lt;br /&gt;Finally, I gave up on trying to deal with the quirks of the Bourne shell under Microsoft Windows, and moved the su into a script on EC2:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;if [ ! `id -un` = &lt;i&gt;username&lt;/i&gt; ]; then su -c "sh -c \"$0 $*\"" &lt;i&gt;username&lt;/i&gt;; exit; fi&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Of course, none of the command parameters are expected to have spaces in them, as the $* would be trouble.  And $@ wouldn't help because of the nested quoting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-57518448713048199?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/57518448713048199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/12/i-have-ant-target-that-runs-some.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/57518448713048199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/57518448713048199'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/12/i-have-ant-target-that-runs-some.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-3077844784010323060</id><published>2010-11-29T00:00:00.000-08:00</published><updated>2010-11-29T00:00:11.628-08:00</updated><title type='text'></title><content type='html'>For storing objects in a database, I chose to serialize the objects in a way that maintains compatibility between object versions.  So Java serialization was out.  My first implementation was to serialize to JSON using Jackson, which was simple because it could serialize and deserialize objects that I was already using.  However, there were more compact serialization schemes.  Apache Thrift and Google Protocol Buffers looked fairly equivalent in functionality.  Both required generating code from some IDL, making them less convenient than JSON.  I chose Protocol Buffers since its serialization seemed to be slightly smaller than that of Thrift.&lt;br /&gt;&lt;br /&gt;In order to continue using the objects that I was using before, since they included annotations and logic that can't be cleanly added to the protobuf-generated code, I used java.beans.Introspector to extract values from the objects to be stored in the database and put them into the protobuf objects and vice-versa.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-3077844784010323060?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/3077844784010323060/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/11/for-storing-objects-in-database-i-chose.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3077844784010323060'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3077844784010323060'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/11/for-storing-objects-in-database-i-chose.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-8202481573445847963</id><published>2010-11-22T00:00:00.000-08:00</published><updated>2010-11-22T00:00:04.760-08:00</updated><title type='text'></title><content type='html'>&lt;a href="http://aws.amazon.com/"&gt;AWS&lt;/a&gt; (Amazon Web Services) is pretty nice.  It not only has what's needed to deploy and scale a web service, but everything can be controlled through their REST (or SOAP) API, so that everything can be automated.&lt;br /&gt;&lt;br /&gt;One thing that should have been obvious was how a service would start when an instance starts.  The first time, I created an instance from a prebuilt image, copied the code to it, then logged in and started it manually.  Eventually, I created an image that included all the code.  I finally figured out that I could start it in /etc/rc.local.&lt;br /&gt;&lt;br /&gt;The next thing I needed to figure out was how to update the software.  Everything would be in a single war file (except for static assets pushed up to the CloudFront CDN (Content Delivery Network)), but automatically building a new image from an existing image with the war file replaced looked difficult.  I could do it manually by starting an instance, replacing the war file, and then creating a new image.  I could automate that manual process.  Another way seems to involve turning the image into a loopback filesystem, replacing the war file in the filesystem, then turning the filesystem back into an image, then uploading the image.  Finally, I figured out that I could just upload the war file to Amazon S3 (Simple Storage Service), and the instance could download the war file from S3 when it starts up, and creating new images is unnecessary.&lt;br /&gt;&lt;br /&gt;However, the process of getting a working image was slow and tedious, since starting and stopping instances, and creating images were all really slow.  Once I had an image that worked, setting up load balancing was trivially easy.  Setting up Auto Scaling also looks very easy, once I figure out what metrics to use for launching and terminating instances.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-8202481573445847963?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/8202481573445847963/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/11/aws-amazon-web-services-is-pretty-nice.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8202481573445847963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8202481573445847963'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/11/aws-amazon-web-services-is-pretty-nice.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-5975349336080538393</id><published>2010-11-15T00:00:00.000-08:00</published><updated>2010-11-15T00:00:07.339-08:00</updated><title type='text'></title><content type='html'>JAX-RS is really nice for writing REST services.  I'm using Jersey 1.3, with Guice 2.0 and jersey-guice to configure things.  However, the Jersey JSON provider is horrible.  It messes up writing empty and single element arrays, and it writes boolean and numerical values as strings.  My first hack around that was to return a JSON string instead of the objects, doing the conversions in-line using Jackson 1.5.  That was ugly, so I overwrote META-INF/services/javax.ws.rs.ext.MessageBodyReader and META-INF/services/javax.ws.rs.ext.MessageBodyWriter in the Jersey jar, replacing the Jersey JSON providers with org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider, and it was much better.&lt;br /&gt;&lt;br /&gt;I also use the Jersey REST client to talk to Facebook.  However, Facebook returns text/javascript;charset=UTF-8 as the content-type, which is not recognized by either the Jersey JSON provider, or the Jackson JAX-RS JSON provider.  Again, the first thing I did was to get the content as an InputStream, which I sent to Jackson for object binding.  Then, I figured that I could just extend the Jackson JSON provider to accept text/javascript and use that class as the JSON provider.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@Provider&lt;br /&gt;@Consumes({MediaType.APPLICATION_JSON, "text/json", "text/javascript"})&lt;br /&gt;@Produces({MediaType.APPLICATION_JSON, "text/json"})&lt;br /&gt;public class MyJaxbJsonProvider extends JacksonJaxbJsonProvider {&lt;br /&gt;    @Override&lt;br /&gt;    protected boolean isJsonType(MediaType mediaType) {&lt;br /&gt;        if (mediaType != null &amp;amp;&amp;amp; "javascript".equals(mediaType.getSubtype()))&lt;br /&gt;            return true;&lt;br /&gt;        return super.isJsonType(mediaType);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, the code no longer has ugly hacks for JSON.  However, any time I get a new Jersey jar, I'll have to overwrite the provider list in the jar, which is ugly.  Perhaps I could put my own javax.ws.rs.ext.MessageBodyReader and javax.ws.rs.ext.MessageBodyWriter in a jar, and have it take precedence, but it didn't work the first time I tried it.  It might depend on the classpath order of the jars, and having to use the classpath order of jar files to override things is also ugly.&lt;br /&gt;&lt;br /&gt;Also on JSON, RFC-4627 says that slashes may be backslash quoted, though the example in section 8 does not backslash quote the slashes.  The JSON from Facebook does backslash quote the slashes, but the JSON produced by Jackson does not.  I wonder why backslash quoted slashes were explicitly included in the JSON specification.  Perhaps it was inherited from Javascript, in which case I wonder why it was that way in Javascript.  My only guess is that it had something to do with regular expressions, if it was from Javascript.  Otherwise, it just seems weird.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-5975349336080538393?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/5975349336080538393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/11/jax-rs-is-really-nice-for-writing-rest.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/5975349336080538393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/5975349336080538393'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/11/jax-rs-is-really-nice-for-writing-rest.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-2850906860468270611</id><published>2010-11-08T00:00:00.000-08:00</published><updated>2010-11-08T00:00:02.549-08:00</updated><title type='text'></title><content type='html'>One thing that bugs me about some of the datacenter hosts that I have to access for one reason or another under a generic developer account that has no write access to anything except /tmp is that there is a long delay while xauth tries to lock $HOME/.Xauthority.  I've explicitly unset DISPLAY, but that makes no difference.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-2850906860468270611?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/2850906860468270611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/11/one-thing-that-bugs-me-about-some-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2850906860468270611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2850906860468270611'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/11/one-thing-that-bugs-me-about-some-of.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-7378954338926075489</id><published>2010-11-01T00:00:00.000-07:00</published><updated>2010-11-01T00:00:15.092-07:00</updated><title type='text'></title><content type='html'>My initial attempt at making an iframe Facebook app immediately ran into a snag.  It seems that if the Safari browser's cookie configuration is "Only from sites I visit", subtitled "Block cookies from third parties and advertisers.", then cookies don't get saved or sent to the iframe.  Which means saving the session id in a cookie fails.  Having sessions is critical, but I don't know if other browsers have this problem, or whether it's acceptable to fail for users that block iframe cookies (or all cookies).  The session id could be stuck in the URL as a matrix parameter with a simple configuration of the servlet container, but it's painful to have to make sure all the URLs that need the session id are rewritten.  Plus, the session id would get leaked in Referer headers.&lt;br /&gt;&lt;br /&gt;Once I made sure all the URLs had the proper rewriting, it still didn't work, because although Glassfish v3 (74.2) rewrites all the URLs, it never recognizes the sessionid in the URL, and creates a new session.  When I switched to Tomcat, it worked with cookies disabled.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-7378954338926075489?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/7378954338926075489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/11/my-initial-attempt-at-making-iframe.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7378954338926075489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7378954338926075489'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/11/my-initial-attempt-at-making-iframe.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-7056065143822613932</id><published>2010-10-25T00:00:00.000-07:00</published><updated>2010-10-25T00:00:03.392-07:00</updated><title type='text'></title><content type='html'>Now, I'm working on Facebook apps using OAuth 2.0, and the &lt;a href="http://tools.ietf.org/html/draft-ietf-oauth-v2-08"&gt;draft specification&lt;/a&gt; says in section 4.2 that JSON is returned when retrieving the access token.  However, Facebook's OAuth 2.0 server returns application/x-www-form-urlencoded data.  I anticipate things changing without notice, so I'll have to code it flexibly.  Of course, it is a &lt;em&gt;draft&lt;/em&gt; specification.&lt;br /&gt;&lt;br /&gt;As for OAuth 2.0 versus OAuth 1.0, it's a little nicer.  Code for computing the signature for OAuth 1.0 is difficult to debug, but, once it's working, it's easy.  On the server side, incorrect nonce handling seems like an obvious hole for replay attacks, and OAuth 2.0 is better in that way.  Also, unencrypted OAuth 1.0 traffic can still be snooped.  Of course, OAuth 2.0 is still subject to traffic analysis.  Of course, with Facebook's reputation on privacy, these differences are irrelevant for most Facebook apps, including the ones I'm working on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-7056065143822613932?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/7056065143822613932/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/10/now-im-working-on-facebook-apps-using.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7056065143822613932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7056065143822613932'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/10/now-im-working-on-facebook-apps-using.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-2302512633760113690</id><published>2010-10-18T00:00:00.000-07:00</published><updated>2010-10-18T00:00:09.573-07:00</updated><title type='text'></title><content type='html'>After using Guice for a little while, I've started learning how to use it better.  I can use @Provides methods to configure objects.  I like being able to install() modules for modularity.&lt;br /&gt;&lt;br /&gt;For webapps, I can have two web.xml files, one pointing to one configuration, and another pointing to another configuration, such as a test configuration, by specifying the different configuration classes as the listener in web.xml files, where the bindings specify different implementations.&lt;br /&gt;&lt;br /&gt;I'm not sure if I like the fluent interface.  It's nice for reading the code, but it makes referring to the javadoc more difficult.  It also creates a bunch temporary objects, but that isn't really a concern.  Guice is supposedly a lot faster than Spring, and the temporary objects probably can be optimized away by escape analysis.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-2302512633760113690?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/2302512633760113690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/10/after-using-guice-for-little-while-ive.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2302512633760113690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2302512633760113690'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/10/after-using-guice-for-little-while-ive.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-1199928051627748385</id><published>2010-10-11T00:00:00.000-07:00</published><updated>2010-10-11T00:00:03.473-07:00</updated><title type='text'></title><content type='html'>I've only had a cursory look at Google Guice, but this is my first impression as compared with Spring, which I've used a lot more.  Using Spring has actually changed the way I approach writing code.&lt;br /&gt;&lt;br /&gt;What I like about Guice is that it is statically type-checked.  Spring's xml configuration is like a dynamically typed language, and more errors slip through to later stages.&lt;br /&gt;&lt;br /&gt;What I like about Spring is that code doesn't need to be written with any Spring-specific calls or constructs, whereas Guice requires Guice-specific annotations.  If I only had to deal with code I've written, it wouldn't matter so much.  However, Spring makes it hooking in code from external libraries more convenient.&lt;br /&gt;&lt;br /&gt;Also, when using Spring, I like being able to specify every last configurable flag in the xml configuration, and anything that truly needs to be tuned can further be extracted into a properties file.  Guice seems to make that level of configuration more inconvenient.  Perhaps I am overlooking some mechanism, but it seems inconvenient to have to insert yet another annotation to name yet another string field that I want to configure, rather than just being able to inject beans.  Guice seems to encourage having a few, high-level, injected objects, rather than every last configurable value injected.&lt;br /&gt;&lt;br /&gt;One nice thing about Guice is that it can inject private fields, while Spring requires a public setter method.  This is just a minor thing though, since, while the implementing class may have some public setters, the public interface that it is being injected as won't have those public setters.  There is also constructor injection, but that is not convenient when there are many parameters to inject.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-1199928051627748385?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/1199928051627748385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/10/ive-only-had-cursory-look-at-google.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1199928051627748385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1199928051627748385'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/10/ive-only-had-cursory-look-at-google.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-6611148362260812912</id><published>2010-10-04T00:00:00.000-07:00</published><updated>2010-10-04T00:00:07.500-07:00</updated><title type='text'></title><content type='html'>I ran across a bug in an Android app that I was working on that had me throwing the phone to the floor multiple times in frustration.  I finally tracked the problem down to SurfaceHolder.Callback.surfaceChanged() being called twice when the phone is held vertically, but only once when the phone is held sideways.  Everyone using the app holds the phone sideways when using the app because the text and icons are all sideways.  However, I had said to myself, "Screw that.  I'm not going to turn the phone sideways just for that."  I don't know what the proper way to fix it is, since I don't know why the code is in SurfaceHolder.Callback.surfaceChanged(), and the person who wrote it had just moved on to another company (Google, actually) a week earlier.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-6611148362260812912?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/6611148362260812912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/10/i-ran-across-bug-in-android-app-that-i.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6611148362260812912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6611148362260812912'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/10/i-ran-across-bug-in-android-app-that-i.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-182180323758081612</id><published>2010-09-27T00:00:00.000-07:00</published><updated>2010-09-27T00:00:02.664-07:00</updated><title type='text'></title><content type='html'>Here's a bug that I recently came across.  I didn't figure it out, and it wasn't code I wrote, but it is an example of gratuitously bad code.&lt;br /&gt;&lt;br /&gt;Originally, I had written some code for a quick-and-dirty demo that went something like:&lt;br /&gt;&lt;pre&gt;    packetType = readPacket(input, buffer);&lt;br /&gt;    switch (packetType) {&lt;br /&gt;    case TYPE1: parseType1(buffer); break;&lt;br /&gt;    case TYPE2: parseType2(buffer); break;&lt;br /&gt;    ...&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;where readPacket() read the appropriate number of bytes into the buffer depending on the packet type.  Something like:&lt;br /&gt;&lt;pre&gt;   packetType = input.read();&lt;br /&gt;    if (packetType == TYPE1) {&lt;br /&gt;        read some stuff into buffer;&lt;br /&gt;    } else {&lt;br /&gt;         count = input.read();&lt;br /&gt;         read count bytes into buffer;&lt;br /&gt;    }&lt;br /&gt;    return packetType;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Somewhere along the line, in a change in source control that was something along the lines of "update to the latest protocol", there were a number of changes, including gratuitously changing the code from something like the above, to something like:&lt;br /&gt;&lt;pre&gt;    packetType = readPacket(input, buffer);&lt;br /&gt;    switch (packetType) {&lt;br /&gt;    case TYPE1: read more stuff from input; break;&lt;br /&gt;    case TYPE2: parseType2(buffer); break;&lt;br /&gt;    ...&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and readPacket() was changed to&lt;br /&gt;&lt;pre&gt;    packetType = input.read();&lt;br /&gt;    if (packetType == TYPE1) {&lt;br /&gt;        return packetType;&lt;br /&gt;    } else {&lt;br /&gt;        count = input.read();&lt;br /&gt;        read count bytes into buffer;&lt;br /&gt;    }&lt;br /&gt;    return packetType;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which all would have worked fine, even though it was a stupid and gratuitous change, except that there was another place that called readPacket(), but ignored the packet.  So, if that other place called readPacket() and got TYPE1, the packet wouldn't be fully read, and subsequent calls to readPacket() would return garbage.  I don't know what the thinking was behind changing the code like that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-182180323758081612?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/182180323758081612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/09/heres-bug-that-i-recently-came-across.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/182180323758081612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/182180323758081612'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/09/heres-bug-that-i-recently-came-across.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-3166503205358167666</id><published>2010-09-20T00:00:00.000-07:00</published><updated>2010-09-20T00:00:02.763-07:00</updated><title type='text'></title><content type='html'>One component of this demo that I'm working on is a server in C++.  The guy who did the work on it was laid off 5 months ago, and now I have to add crap to it.  Most of it was 3rd-party code.  I don't know what changes have been made to it, since it was checked into source control in one big chunk 9 months ago.  However, there is one directory that has our specific configuration files and build and startup and shutdown scripts.&lt;br /&gt;&lt;br /&gt;I found the build, startup, and shutdown scripts kind of annoying.  They all assumed that the scripts would be run from the directory that the script were in, which I don't like to do.  I prefer running /absolute/path/to/the/script, rather than cd /absolute/path/to/the, then ./script.  So I added cd `dirname $0` to the top of all the scripts.  Another goofy thing in the scripts were the use of pushd somedirectory &gt;/dev/null, and then popd &gt;/dev/null.  Personally, I use directory stacks interactively all the time, and often have 3 or 4 directories that I switch between, but, for the script, cd somedirectory, then cd .. would work just as well.&lt;br /&gt;&lt;br /&gt;As for the C++ server, I had to add a feature, which I did.  And it worked some of the time, but mysteriously didn't work some of the time.  There was a logging framework that I tried to use, and I spent a day trying to use it.  When I tried making a new logger class, and tried enabling it, the server crashed.  Finally, I just hacked in some code that fopened a file, and vfprintfed crap directly to it, and figured out that I had added an uninitialized variable to a class, and, depending on what value it had, the feature worked or didn't.  So I fixed it by initializing it in the constructor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-3166503205358167666?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/3166503205358167666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/09/one-component-of-this-demo-that-im.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3166503205358167666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3166503205358167666'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/09/one-component-of-this-demo-that-im.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-3947608070119288800</id><published>2010-09-13T00:00:00.000-07:00</published><updated>2010-09-13T00:00:05.289-07:00</updated><title type='text'></title><content type='html'>There is some demo code at work that's been around for around 10 months, and I've added various features to it from time to time.  Also, from time to time, the deployed code has to be put in a "known state" to actually do the demos.  A month or two ago, some other guy added a feature, which makes the user interface fancier, so his changes need to be in all the demos, but he never checked anything into source control.  Since then, I've added some features, all of them checked in.  So now when there is a demo, this guy has to merge my changes into his code and then deploy it on the demo system.  Except that what has actually happened is that they go back to the code that he originally deployed over 3 months ago, which doesn't have any the features I've added, which include changes that make the platform more robust.  I can't deploy the demo including his features because I don't have his code.&lt;br /&gt;&lt;br /&gt;One of these days, I'm going to ask him why he doesn't check his crap in.&lt;br /&gt;&lt;br /&gt;I don't understand how some people can work on stuff while rarely interacting source control.  I update my source trees often.  I update before starting work.  I merge in changes periodically during work.  I merge in changes when I'm ready to check stuff in.  I check stuff in when I'm done working on it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-3947608070119288800?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/3947608070119288800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/09/there-is-some-demo-code-at-work-thats.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3947608070119288800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3947608070119288800'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/09/there-is-some-demo-code-at-work-thats.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-7586576693438169956</id><published>2010-09-06T00:00:00.000-07:00</published><updated>2010-09-06T00:00:01.672-07:00</updated><title type='text'></title><content type='html'>There has been a bunch of attrition at work, so I have to help taking over some Android code.  So, to learn the Android platform, I decided to make a sample application that receives incoming SMS messages and send them through the text-to-speech processor.  I put the code on &lt;a href="http://github.com/qpliu/TXTSpeak"&gt;github&lt;/a&gt;.  I managed to get it to work on an emulator in a couple of days, as the Android platform is pretty easy to learn and pretty well documented.  I haven't tried it on a real phone, since I wrote it for Android 2.1, and phones at work run Android 1.6.&lt;br /&gt;&lt;br /&gt;The one thing that I had problems with was the service lifecycle interfering with the asynchronous text-to-speech interface.  My ugly solution was to have the service post an empty intent to itself while the text-to-speech was still speaking to keep the service alive, since the text-to-speech instance would have been considered leaked if it isn't shutdown when the service is destroyed.  If I continue working on Android applications, I'll probably find a better way to do it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-7586576693438169956?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/7586576693438169956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/09/there-has-been-bunch-of-attrition-at.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7586576693438169956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7586576693438169956'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/09/there-has-been-bunch-of-attrition-at.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-4829028139996021604</id><published>2010-08-30T00:00:00.000-07:00</published><updated>2010-08-30T00:00:07.467-07:00</updated><title type='text'></title><content type='html'>I just started using &lt;a href="http://git-scm.com/"&gt;git&lt;/a&gt; for version control, and made some free repositories on &lt;a href="http://github.com"&gt;github&lt;/a&gt;.  I haven't tried anything beyond the very basics of creating a repository and committing and fetching code from multiple sites.  I haven't made any branches or done any rebasing.  For the basics, the only new concept I had to learn was the index, which I glossed over when first reading the documentation.  After playing around a bit, I got a little confused, then kind of figured out what was going on, then read the documentation again, and it became clear.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-4829028139996021604?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/4829028139996021604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/08/i-just-started-using-git-for-version.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/4829028139996021604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/4829028139996021604'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/08/i-just-started-using-git-for-version.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-6137051196755496949</id><published>2010-08-23T00:00:00.000-07:00</published><updated>2010-08-23T00:00:00.196-07:00</updated><title type='text'></title><content type='html'>More &lt;a href="http://projecteuler.net"&gt;Project Euler&lt;/a&gt; problems.&lt;br /&gt;&lt;br /&gt;For problem 51, I only had to try replacing the 0s, 1s and 2s, since there had to be 8 values in the family.  And I didn't have to try replacing 1s with 0s or 2s with 1s or 0s, since those would be redundant.&lt;br /&gt;&lt;br /&gt;I just did a brute force search from 1 on up for problem 52.  It would be more complicated and maybe faster to skip numbers where the most significant digit is not 1, but the answer wasn't all that big, so it wouldn't be significantly faster, if at all.&lt;br /&gt;&lt;br /&gt;For problem 53, since &lt;sup&gt;n&lt;/sup&gt;C&lt;sub&gt;0&lt;/sub&gt; = &lt;sup&gt;n&lt;/sup&gt;C&lt;sub&gt;n&lt;/sub&gt; = 1, and C increases rapidly from the edges and peaks at the middle, I counted the values under a million for 0 &amp;le; r &amp;le; n/2, doubled it and subtracted.&lt;br /&gt;&lt;br /&gt;For problem 54, using Haskell's deriving (Ord) with an appropriate data structure and mapping the card values to values that ordered the ace, face cards, and ten correctly made it simple.  Also, there were no instances of A 2 3 4 5 in the data, which, if considered a straight, would have had to have a special-case constructor to be ordered correctly.&lt;br /&gt;&lt;br /&gt;I just brute-forced problem 55 over the range 1..9999.&lt;br /&gt;&lt;br /&gt;For problem 56, the upper bound for the sum of digits is 9b log&lt;sub&gt;10&lt;/sub&gt;a, and log&lt;sub&gt;10&lt;/sub&gt;a &lt; 2, so the upper bound is 18b.  So the maximum value for b = 99 establishes a lower bound for b that needs to be searched.  Subsequent new maximums for b &amp;lt; 99 can raise that lower bound.  I wound up searching 1 &amp;le; a &amp;le; 99 for 54 &amp;le; b &amp;le; 99.&lt;br /&gt;&lt;br /&gt;For problem 57, I found that doing head (show numerator) &lt; head (show denominator) was faster than counting all the digits, as it's known that numerator/denominator is approximately 1.4.&lt;br /&gt;&lt;br /&gt;For problem 58, I just did a brute force iteration over each square, with running counts of the total and the number of primes.&lt;br /&gt;&lt;br /&gt;For problem 59, I printed out every 3rd character decoded with each of the 26 possible key characters, and then visually chose each of the 3 characters in the key.&lt;br /&gt;&lt;br /&gt;For problem 60, I could only come up with a super slow solution, though it did come up with the answer in about 10 minutes, and ruled out other possible answers after 30 more minutes.  I made a very wide, shallow tree, spitting out results when reaching a depth of 5.  I had to do a bunch of redundant calculations, because although I had a branch starting with 3,7,109,... I still needed branches starting with 3,..., 3,7,..., 3,109,..., 7,..., 7,109,..., 109,....  I'm thinking that a graph-based algorithm, instead of a tree-based algorithm would be faster, should I revisit this problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-6137051196755496949?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/6137051196755496949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/08/more-project-euler-problems.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6137051196755496949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6137051196755496949'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/08/more-project-euler-problems.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-2748330763431231138</id><published>2010-08-16T00:00:00.000-07:00</published><updated>2010-08-16T00:00:06.961-07:00</updated><title type='text'></title><content type='html'>Looking at more &lt;a href="http://projecteuler.net"&gt;Project Euler&lt;/a&gt; problems.&lt;br /&gt;&lt;br /&gt;I thought problem 41 was going to be tough, but there are only 9! = 362880 nine-digit numbers to consider, and even fewer 8-digit numbers to consider, etc, so it was just a matter of checking for the first prime permutation.&lt;br /&gt;&lt;br /&gt;Problem 42 was straightforward.  I made a list of triangle numbers up to the maximum word value, then filtered the word values and counted.&lt;br /&gt;&lt;br /&gt;For problem 43, I started by taking all multiples of 17 under 1000, filtering out any with repeated digits.  Adding the 4th digit made the set 7 times bigger, but removing those that did not have the divisible by 13 property made the set about half the size.  Iterate for the remaining digits.&lt;br /&gt;&lt;br /&gt;I couldn't find a reasonable way to solve problem 44.  It involves finding 4 pentagonal numbers, p&lt;sub&gt;i&lt;/sub&gt;, p&lt;sub&gt;j&lt;/sub&gt;, p&lt;sub&gt;k&lt;/sub&gt;, p&lt;sub&gt;l&lt;/sub&gt;, where p&lt;sub&gt;i&lt;/sub&gt; &amp;le; p&lt;sub&gt;j&lt;/sub&gt; &amp;lt; p&lt;sub&gt;k&lt;/sub&gt; &amp;lt; p&lt;sub&gt;l&lt;/sub&gt;, and p&lt;sub&gt;i&lt;/sub&gt; = p&lt;sub&gt;k&lt;/sub&gt; - p&lt;sub&gt;j&lt;/sub&gt;, and p&lt;sub&gt;j&lt;/sub&gt; + p&lt;sub&gt;k&lt;/sub&gt; = p&lt;sub&gt;l&lt;/sub&gt;, where p&lt;sub&gt;i&lt;/sub&gt; is minimized.  For a given i, there's an upper bound for j, such that p&lt;sub&gt;i&lt;/sub&gt; &amp;ge; p&lt;sub&gt;j+1&lt;/sub&gt; - p&lt;sub&gt;j&lt;/sub&gt;, and the upper bound for j is O(i&lt;sup&gt;2&lt;/sup&gt;), which means a brute-force search over i gets extremely slow.  However, since I didn't have any better ideas, I searched i from 1 to about 350 or so without finding a solution, and gave up.&lt;br /&gt;&lt;br /&gt;For problem 45, I made a list of hexagonal numbers, filtered out those that weren't pentagonal or triangle, and took the 3rd number in the resulting list, the first two being 1 and 40755.  It would have been slightly slower to make a list of pentagonal or triangle numbers, and filter out those that weren't the other types.&lt;br /&gt;&lt;br /&gt;For problem 46, I iterated over non-prime odd numbers, building up a list of primes and doubled squares less than it, stopping when none of the primes could be added to one of the doubled squares to get that number.&lt;br /&gt;&lt;br /&gt;In problem 47, I only had to check every 4th number until one had at least 4 factors, then check the previous one, the one before that, and the one before that.  If any didn't have at least 4 factors, I could jump forward 4 from that.&lt;br /&gt;&lt;br /&gt;For problem 48, using mod 10&lt;sup&gt;10&lt;/sup&gt; arithmetic means not having to add gigantic numbers, while still getting the last 10 digits.&lt;br /&gt;&lt;br /&gt;For problem 49, I took all the 4 digit primes and grouped the ones that were permutations of each other together, then searched each group for a qualifying triplet.&lt;br /&gt;&lt;br /&gt;For problem 50, I found the longest prime sum starting with 2, as well as the list of primes after the last term of the sum.  Then, I subtracted 2 and added the next largest prime, looking for the longest sum starting with 3, and iterating until subtracting the next smallest prime and adding enough of the next largest primes to make the sum have more terms than the current longest sum resulted in a sum more than a million.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-2748330763431231138?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/2748330763431231138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/08/looking-at-more-project-euler-problems.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2748330763431231138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2748330763431231138'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/08/looking-at-more-project-euler-problems.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-4855505285827820850</id><published>2010-08-09T00:00:00.000-07:00</published><updated>2010-08-09T00:00:07.165-07:00</updated><title type='text'></title><content type='html'>Looking at the 4th ten &lt;a href="http://projecteuler.net"&gt;Project Euler&lt;/a&gt; problems.&lt;br /&gt;&lt;br /&gt;Problem 31 is a straightforward recursive count.  Once you get to the 1p, the number of combinations is 1.&lt;br /&gt;&lt;br /&gt;For problem 32, 99&amp;times;99 = 9801 and 111&amp;times;111 = 12321, so all the solutions have to be a two-digit number &amp;times; a three-digit number resulting in a four-digit number.  I did a brute-force search through all the combinations of 5 digits of the multiplicands.&lt;br /&gt;&lt;br /&gt;Problem 33 just involved searching with 1 through 9 to see if any pair of digits had the property, so that was a small search.  Also, there were only 36 pairs of digits to check.&lt;br /&gt;&lt;br /&gt;Problem 34 is just like problem 30 with a larger bound.&lt;br /&gt;&lt;br /&gt;For problem 35, I partitioned the primes by number of digits, then filtered out the numbers that were not the minimum of the digit rotations, which conveniently eliminated all numbers with zeros.  I then filtered out the numbers for which not all of the rotated numbers were in its partition, which eliminated 11.    111, 1111, 11111, 111111 are all not prime.  Then multiple the size of each partition by its number of digits, sum, add 1 for 11 gives the answer.&lt;br /&gt;&lt;br /&gt;Problem 36 was a brute-force filter.  Since leading zeros weren't allowed, even numbers could be eliminated, cutting the problem in half.&lt;br /&gt;&lt;br /&gt;For problem 37, I built lists of n-digit primes that could be truncated from the left to n-1-digit primes, and lists of n-digit primes that could be truncated from the right to n-1-digit primes.  The intersection of the left and right lists gives the 11 numbers.&lt;br /&gt;&lt;br /&gt;From the example in problem 38, the first digit had to be a 9, so it was just a matter of searching 91..98, 912..987, 9123..9876, and 91234..98765.&lt;br /&gt;&lt;br /&gt;For problem 39, p/3 &lt; c &lt; p-3, and c/2 &lt; b &lt; c-1.  After that, I just did a brute-force search, which was kind of slow.&lt;br /&gt;&lt;br /&gt;Problem 40 is just multiplying 7 single-digit numbers, and at least 2 of them are 1.  It's straightforward to figure out those numbers, and, as it turns out, the product of those numbers is simple to mentally compute.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-4855505285827820850?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/4855505285827820850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/08/looking-at-4th-ten-project-euler.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/4855505285827820850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/4855505285827820850'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/08/looking-at-4th-ten-project-euler.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-8082504661724905138</id><published>2010-08-02T00:00:00.000-07:00</published><updated>2010-08-02T00:00:02.077-07:00</updated><title type='text'></title><content type='html'>I wanted more immediate feedback about my &lt;a href="http://www.rockband.com"&gt;Rock Band&lt;/a&gt; scores, so I modified the code I wrote that takes a picture of the television screen and does OCR (optical character recognition) to figure out what song was just played, and run text-to-speech with the name of the song and my high score.  It works about half the time.  But when it works, I get to know if I got a new high score without having to go over to the computer and check, which means I can be ready to play the next song.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-8082504661724905138?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/8082504661724905138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/08/i-wanted-more-immediate-feedback-about.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8082504661724905138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8082504661724905138'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/08/i-wanted-more-immediate-feedback-about.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-6610976706903143224</id><published>2010-07-26T00:00:00.000-07:00</published><updated>2010-07-26T00:00:01.429-07:00</updated><title type='text'></title><content type='html'>Continuing to look at the &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt; problems.  The third 10 are a little more difficult than the previous 20.&lt;br /&gt;&lt;br /&gt;My Haskell solution for problem 21 was too slow.  So, in Java, I made a table of the sum of the divisors for the numbers from 1 to 9999, then added up the numbers that pointed at each other, as well as the numbers in the table that paired with numbers greater than 9999, and it was reasonably fast.&lt;br /&gt;&lt;br /&gt;Problem 22 was straightforward.&lt;br /&gt;&lt;br /&gt;I could not write a fast algorithm for problem 23 in Haskell.  So, in Java, I made a table of whether the number is abundant for 1 to 28123.  Then, each number from 1 to 28123 could be tested by testing for pairs of trues in the table where the indices added up to the number, which should be less than around 200 million tests, and short-circuiting after the first pair is found means the actual number of tests should be much lower than that.&lt;br /&gt;&lt;br /&gt;Problem 24 doesn't require much computation.  The first element of the nth permutation is the (n-1)/m!+1th element, where m+1 is the number of elements, and the rest of the nth permutation is the remainder of (n-1)/m!+1th permutation of the remaining elements.&lt;br /&gt;&lt;br /&gt;Problem 25 was straightforward.&lt;br /&gt;&lt;br /&gt;My solution to problem 26 was kind of slow, but not excessively slow.  I calculated the cycle length by making a list of the remainders and searched the list of remainders for repeats with each new digit in the quotient.  After that, it was a brute-force maximum search: &lt;code&gt;snd $ maximum $ map (\ n -&amp;gt; (cycleLength n,n)) [1..1000]&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;My solution for problem 27 was kind of slow.  b must be a prime under 1000 due to n=0, so there 168 possibilities for b.  Given b and n, p = n&lt;sup&gt;2&lt;/sup&gt; + an + b, where p is prime, so a = (p - b)/n - n, so p - b has to be a multiple of n, so I made a list of primes satisfying that condition, which can be mapped to a list of values for a, which can be filtered for |a| &amp;lt; 1000.  Then, I brute-force searched the 168 values of b for the maximum n and the corresponding a.&lt;br /&gt;&lt;br /&gt;Problem 28 doesn't require much computation.  The numbers on the corner of the nxn square, where n is odd, is a simple function of n, so the numbers on the diagonals can be added by recursively adding the diagonals of the (n-2)x(n-2) square.&lt;br /&gt;&lt;br /&gt;For problem 29, any pair that has a&lt;sup&gt;i&lt;/sup&gt; &amp;le; 100, where i &amp;gt; 1 and i divides b is not distinct and can be filtered out.&lt;br /&gt;&lt;br /&gt;My solution for problem 30 was quite slow.  Since 6&amp;times;9&lt;sup&gt;5&lt;/sup&gt; = 354294, 299999 is an upper bound.  2&lt;sup&gt;5&lt;/sup&gt; + 5&amp;times;9&lt;sup&gt;5&lt;/sup&gt; = 295277, 1&lt;sup&gt;5&lt;/sup&gt; + 5&amp;times;9&lt;sup&gt;5&lt;/sup&gt; = 295246, so I used 295246 as an upper bound for the brute force search.  After working on problem 34, which is almost the same problem with a much bigger upper bound, I made the search faster by searching by 10s and only going through the 1s digits if the sum of the other digits is between the number + 9 - 9&lt;sup&gt;5&lt;/sup&gt; and the number.  This could be generalized to further prune the search by only considering the most significant digits, and only iterating through less significant digits if sum of the digits is within range of the number.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-6610976706903143224?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/6610976706903143224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/07/continuing-to-look-at-project-euler_26.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6610976706903143224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6610976706903143224'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/07/continuing-to-look-at-project-euler_26.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-2454159395520502049</id><published>2010-07-19T00:00:00.000-07:00</published><updated>2010-07-19T00:00:03.942-07:00</updated><title type='text'></title><content type='html'>Continuing to look at the &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt; problems.  The second 10 are a little more difficult than the first 10.&lt;br /&gt;&lt;br /&gt;Problem 11 is yet another search.  I used &lt;code&gt;transpose . zipWith drop [0..]&lt;/code&gt; to get a quarter of the diagonals, and combined it with various uses of &lt;code&gt;reverse&lt;/code&gt; to get the rest of the diagonals.  The result was on a diagonal.&lt;br /&gt;&lt;br /&gt;My solution to problem 12 was horribly slow with hugs, so I solved it in Java.  The algorithm I used should be O(N&lt;sup&gt;3/2&lt;/sup&gt;), and the answer I got was between 50 million and 100 million.  Perhaps my calculation of triangle numbers was O(N&lt;sup&gt;2&lt;/sup&gt;) in hugs, instead of O(N), causing the calculation to be O(N&lt;sup&gt;5/2&lt;/sup&gt;).&lt;br /&gt;&lt;br /&gt;Problem 13 might have been more of a challenge when restricted to fixed size integer arithmetic.  As it was, &lt;code&gt;take 10 . show . sum&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;My Haskell solution to problem 14 was horribly slow, so I solved it in Java by tabulating the results under a million and using the recursive formula whenever it went over a million.&lt;br /&gt;&lt;br /&gt;My Haskell solution to problem 15 was horribly slow, so I solved it in Java by tabulating the results by building on the previously tabulated results for smaller grids, which should be O(N&lt;sup&gt;2&lt;/sup&gt;).&lt;br /&gt;&lt;br /&gt;Problem 16, like problem 13, was a simple one-liner that would have been much more difficult when restricted to fixed size integers.&lt;br /&gt;&lt;br /&gt;Problem 17 is just a matter of counting correctly, without any nontrivial mathematical reasoning or computation.&lt;br /&gt;&lt;br /&gt;Problem 18 (and problem 67) can be solved with pretty much a one-liner: &lt;code&gt;foldr1 (\ row sums -&amp;gt; zipWith3 (\ i l r -&amp;gt; i + max l r) row sums (tail sums))&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Problem 19 is an easy brute-force iteration, with only 1200 months to consider.  The 100 and 400 year rules can be ignored, given the range.&lt;br /&gt;&lt;br /&gt;Problem 20 is a simple one-liner just like problem 16, where the challenge is mainly for those restricted to fixed-size integers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-2454159395520502049?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/2454159395520502049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/07/continuing-to-look-at-project-euler.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2454159395520502049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2454159395520502049'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/07/continuing-to-look-at-project-euler.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-8480792544678785427</id><published>2010-07-12T00:00:00.000-07:00</published><updated>2010-07-12T00:00:01.574-07:00</updated><title type='text'></title><content type='html'>When there was only busy-work at work, I started working through the &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt; problems.  For the most part, I used the hugs implementation of Haskell, since the problems ought to be solvable without a huge amount of computation.  However, some of my solutions were way too slow, so I used Java to solve some of the problems.  I haven't submitted any of my answers, so I don't have that verification that my answers are correct.&lt;br /&gt;&lt;br /&gt;Problem 1 was a simple one-liner in Haskell&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; p1 = sum [3,6..999] + sum [5,10..999] - sum [15,30..999]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Problem 2 was a simple 2-liner in Haskell.&lt;br /&gt;&lt;br /&gt;For problem 3, I started by computing a list of primes.  After getting the answer, I realized that calculating the primes was superfluous.  I could just divide out all factors, starting from 2, regardless if they were prime or not, and the remainder would be the largest prime factor.&lt;br /&gt;&lt;br /&gt;I just brute forced problem 4, though I can halve the search space since multiplication is commutative.&lt;br /&gt;&lt;br /&gt;Problem 5 was a simple one-liner.  Haskell's Prelude provides gcd.&lt;br /&gt;&lt;br /&gt;Problem 6 was another simple one-liner.&lt;br /&gt;&lt;br /&gt;My solution for problem 7 was pretty slow.  Adding a type declaration: &lt;code&gt;primes :: [Int]&lt;/code&gt;, made it over 3 times faster, though still slow, with hugs.  The inferred type would have been &lt;code&gt;primes :: [Integer]&lt;/code&gt;, but since all of the relevant numbers fit into signed 32-bit integers, &lt;code&gt;[Int]&lt;/code&gt; would still give the correct result.  I sped up a number of slow solutions by adding &lt;code&gt;Int&lt;/code&gt; declarations.&lt;br /&gt;&lt;br /&gt;I brute forced problem 8.  Since the last digit was a 0, I could just do &lt;code&gt;product . take 5&lt;/code&gt; and not worry about a spurious result, which I would have had to worry about if the number had ended with 09999.&lt;br /&gt;&lt;br /&gt;Problem 9 was another brute-force search.  Since &lt;code&gt;1000 &amp;gt; c &amp;gt; b &amp;gt; a &amp;gt; 0&lt;/code&gt;, I could limit the search to &lt;code&gt;1000 &amp;gt; c &amp;gt; 333&lt;/code&gt; and &lt;code&gt;c &amp;gt; b &amp;gt; c/2&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;My solution to problem 10 in Haskell was just too slow using hugs, so I wrote basically the same algorithm in about 20 lines of Java, which was fast.  The result had to be a long, since it was too big to for 32-bit integers.  I manually stored the computed primes in an array in the Java solution.  Perhaps hugs wasn't memoizing the list of primes that was being computed, causing the algorithm that was supposed to be O(N&lt;sup&gt;3/2&lt;/sup&gt;) to be O(N&lt;sup&gt;2&lt;/sup&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-8480792544678785427?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/8480792544678785427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/07/when-there-was-only-busy-work-at-work-i.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8480792544678785427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8480792544678785427'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/07/when-there-was-only-busy-work-at-work-i.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-6269601938908419063</id><published>2010-07-05T00:00:00.000-07:00</published><updated>2010-07-05T00:00:01.010-07:00</updated><title type='text'></title><content type='html'>The service that I work on interfaces with things that other people work on.  One problem that came up multiple times is that these other systems have hard-coded invalid assumptions that have worked so far, for various reasons.  One of the reasons is that one of the early features that didn't fit those assumptions simply got reclassified as unsupported and has been removed from every release.  Due to these problems, I'll have to account for these hard-coded assumptions in these other systems when adding new features in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-6269601938908419063?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/6269601938908419063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/07/service-that-i-work-on-interfaces-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6269601938908419063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6269601938908419063'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/07/service-that-i-work-on-interfaces-with.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-2256131172318578955</id><published>2010-06-28T00:00:00.000-07:00</published><updated>2010-06-28T00:00:04.326-07:00</updated><title type='text'></title><content type='html'>I got pulled into yet another demo, involving building yet another prototype.  I managed to get something functional in under a week, in about 2000 lines of Java.  The next two weeks involved rewriting lots of the code either due to my misunderstanding of what it was supposed to do, or changes in what it should do after having something available to play with.  Since I was the only one working on the code, I felt free to rewrite big chunks of it.  The demo ended up being about 3000 lines of Java and seems to have gone successfully.&lt;br /&gt;&lt;br /&gt;Two things, which I've said before, apply to this experience.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Being able to throw away the first few iterations is valuable.  The design of later iterations can incorporate issues that weren't forseen in the earlier iterations.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Static typing makes replacing large chunks of code manageable.  The compiler caught numerous little oversights, whereas using a dynamically typed language would have been much more painful.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;So, for prototyping and rapid iteration, I strongly prefer using statically typed languages.&lt;br /&gt;&lt;br /&gt;For an established code base that has many people working on it, rewriting large chunks of code is less of an option.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;It's harder to understand all of the issues in a large codebase.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Management conservatism discourages potentially disruptive changes.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-2256131172318578955?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/2256131172318578955/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/06/i-got-pulled-into-yet-another-demo.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2256131172318578955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2256131172318578955'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/06/i-got-pulled-into-yet-another-demo.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-1526028876232761886</id><published>2010-06-21T00:00:00.000-07:00</published><updated>2010-06-21T00:00:04.994-07:00</updated><title type='text'></title><content type='html'>After setting up my computer to take pictures of my television screen when finishing a &lt;a href="http://www.rockband.com/"&gt;Rock Band&lt;/a&gt; song, I can go back and see if I got any new high scores afterwards.  However, the leaderboard interface is limited by the controllers and navigating hundreds of songs is clumsy, so I came up with a way to make the computer do most of that work.  I can get my scores from &lt;a href="http://rockbandscores.com/"&gt;rockbandscores.com&lt;/a&gt; in csv format, and use OCR (optical character recognition) software to get the name of the song out of the picture.&lt;br /&gt;&lt;br /&gt;The scores and song names show up in two different ways.  In the middle of a set, the song name appears at the bottom left of the screen.  At the end of the set, the song name appears at the top of the screen, in uppercase, and in a different font.  There are also lots of non-textual graphics on the screen.  However, the OCR software doesn't have to be anywhere near perfect, since all it needs to do is to enable distinguishing between a limited set of a few hundred song titles.  So I got &lt;a href="http://www.gnu.org/software/ocrad/"&gt;ocrad&lt;/a&gt;, which is free, lightweight, and fast, though not very sophisticated or flexible.&lt;br /&gt;&lt;br /&gt;I send the upper part of each image and the lower left of each image through OCR after processing the piece of the image into monochrome, selecting the whitest and brightest pixels.  Originally, I selected for the brightest pixels, but I found that also selecting for the whitest pixels worked much better.  There are still lots of non-text clutter left, which the OCR software interprets.  So after gathering data on what results the OCR software got from various pictures, I made and refined a heuristic for matching the OCR results with the song titles.&lt;br /&gt;&lt;br /&gt;Here are some initial results after getting it to work pretty well.  First, a song in the middle of a setlist:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_tSP-m6DKhqI/S2TqkJQVD4I/AAAAAAAAAWE/0EiXPdtXryU/s1600-h/1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_tSP-m6DKhqI/S2TqkJQVD4I/AAAAAAAAAWE/0EiXPdtXryU/s320/1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5432724957196259202" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Processing the upper part and the lower left part causes the song title to stand out in the lower left.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_tSP-m6DKhqI/S2Tqkk9NexI/AAAAAAAAAWM/QDzwmX16vSA/s1600-h/1a.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_tSP-m6DKhqI/S2Tqkk9NexI/AAAAAAAAAWM/QDzwmX16vSA/s320/1a.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5432724964632263442" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The OCR software does a reasonable job on the lower left:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;M1dn19htR1d9r. . .&lt;br /&gt;\ a ' ;' '' .. , 1&lt;br /&gt;_-__.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The OCR text is good enough that it matches one song in the scores.csv file, the correct one, and I did not get a new high score:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[Midnight Rider, The Allman Brothers Band, GUITAR:75218 6.18, DRUMS:127100 5.37]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After finishing the set:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_tSP-m6DKhqI/S2TqlQ-PFyI/AAAAAAAAAWU/odFwmmClH18/s1600-h/11.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_tSP-m6DKhqI/S2TqlQ-PFyI/AAAAAAAAAWU/odFwmmClH18/s320/11.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5432724976447723298" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Processing the upper part and lower left part of the image causes the song name and score to show up cleanly in the upper part:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_tSP-m6DKhqI/S2Tql3EwuwI/AAAAAAAAAWc/VfXoYNzJIAM/s1600-h/11a.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_tSP-m6DKhqI/S2Tql3EwuwI/AAAAAAAAAWc/VfXoYNzJIAM/s320/11a.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5432724986675641090" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The OCR software returns:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;FRRNH11N'5 7DWER&lt;br /&gt;225,225 _K1,v,v_&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and the A in the picture does look like an R, and the K does look like an H, and all the other misread characters do look like the characters returned by the OCR software.  The score was also correctly recognized, but that usually doesn't happen.&lt;br /&gt;&lt;br /&gt;Matching the text with the scores.csv file, I got a new high score:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[Franklin's Tower, Grateful Dead, DRUMS:223275 5.98, GUITAR:155807 6.67]&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-1526028876232761886?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/1526028876232761886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/06/after-setting-up-my-computer-to-take.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1526028876232761886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1526028876232761886'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/06/after-setting-up-my-computer-to-take.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_tSP-m6DKhqI/S2TqkJQVD4I/AAAAAAAAAWE/0EiXPdtXryU/s72-c/1.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-3803368328948529297</id><published>2010-06-14T00:00:00.000-07:00</published><updated>2010-06-14T00:00:00.473-07:00</updated><title type='text'></title><content type='html'>One thing I like to do is play &lt;a href="http://www.rockband.com/"&gt;Rock Band&lt;/a&gt;.  However, I often find that I don't remember what songs I just played in a playlist, and sometimes I want to check and see if I got a new high score.  My first thought was to sniff the packets sent to the online leaderboards and pull the songs and the scores out of that data.  Unfortunately, the packets are encrypted, so I gave up on that idea.  But I had a new idea.  I could point my computer's camera at the screen and record a video.&lt;br /&gt;&lt;br /&gt;Making a video of the gameplay would eat up disk space and it would be a pain to go through a long video to see all the songs.  But, going back to my first idea of sniffing packets, I could have some scheme of taking pictures and saving the ones around the time when packets were sent to the leaderboards.  After finding out how to take pictures using the quicktime API and trying it out, I wrote some code that took a picture every 5 seconds, and interleaved the pictures with tcpdump output.  I found that 32 byte packets were being sent every few seconds to Xbox Live, and 80 byte packets were being sent every once in a while, but larger packets were always sent after finishing a song.  So then I wrote it to take a few pictures when seeing the larger packets.  It worked really well.  It takes some extraneous pictures due to other packets.  Fortunately, I don't have lots of Xbox friends that would cause lots of notification packets.&lt;br /&gt;&lt;br /&gt;Now I can play a dozen or so songs, and then go back and see how I did, instead of worrying about not remembering what I just played after playing only 3 or 4 songs.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import java.io.BufferedReader;&lt;br /&gt;import java.io.File;&lt;br /&gt;import java.io.FileOutputStream;&lt;br /&gt;import java.io.InputStreamReader;&lt;br /&gt;import java.io.PrintStream;&lt;br /&gt;import java.util.Date;&lt;br /&gt;import java.util.concurrent.ArrayBlockingQueue;&lt;br /&gt;import java.util.concurrent.TimeUnit;&lt;br /&gt;import quicktime.QTSession;&lt;br /&gt;import quicktime.io.QTFile;&lt;br /&gt;import quicktime.qd.Pict;&lt;br /&gt;import quicktime.qd.QDConstants;&lt;br /&gt;import quicktime.qd.QDGraphics;&lt;br /&gt;import quicktime.qd.QDRect;&lt;br /&gt;import quicktime.std.StdQTConstants4;&lt;br /&gt;import quicktime.std.image.GraphicsExporter;&lt;br /&gt;import quicktime.std.sg.SequenceGrabber;&lt;br /&gt;&lt;br /&gt;public class Scorer {&lt;br /&gt;    private static ArrayBlockingQueue&amp;lt;Long&amp;gt; queue = new ArrayBlockingQueue&amp;lt;Long&amp;gt;(20);&lt;br /&gt;    private static boolean running = true;&lt;br /&gt;&lt;br /&gt;    private static void capturePhoto(String filename) throws Exception {&lt;br /&gt;        try {&lt;br /&gt;            QTSession.open();&lt;br /&gt;            QDRect qdRect = new QDRect(640, 480);&lt;br /&gt;            QDGraphics qdGraphics = new QDGraphics(qdRect);&lt;br /&gt;            SequenceGrabber sequenceGrabber = new SequenceGrabber();&lt;br /&gt;            sequenceGrabber.setGWorld(qdGraphics, null);&lt;br /&gt;            GraphicsExporter graphicsExporter = new GraphicsExporter(StdQTConstants4.kQTFileTypePNG);&lt;br /&gt;            graphicsExporter.setInputPicture(Pict.fromSequenceGrabber(sequenceGrabber, qdRect, 0, 0));&lt;br /&gt;            graphicsExporter.setOutputFile(new QTFile(filename));&lt;br /&gt;            graphicsExporter.doExport();&lt;br /&gt;        } finally {&lt;br /&gt;            QTSession.close();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static void recorder(String dir) {&lt;br /&gt;        try {&lt;br /&gt;            PrintStream out = new PrintStream(new FileOutputStream(dir + "index.html"));&lt;br /&gt;            out.println("&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;");&lt;br /&gt;            int i = 0;&lt;br /&gt;            long t = 0L;&lt;br /&gt;            while (running) {&lt;br /&gt;                queue.take();&lt;br /&gt;                if (System.currentTimeMillis() - t &amp;lt; 30000L)&lt;br /&gt;                    continue;&lt;br /&gt;                out.println("&amp;lt;br&amp;gt;Start:" + new Date() + "&amp;lt;br&amp;gt;");&lt;br /&gt;                for (int j = 0; j &amp;lt; 3; j++) {&lt;br /&gt;                    capturePhoto(dir + i + ".png");&lt;br /&gt;                    out.println("&amp;lt;img src=\"" + i + ".png\"&amp;gt;");&lt;br /&gt;                    i++;&lt;br /&gt;                    TimeUnit.SECONDS.sleep(1);&lt;br /&gt;                }&lt;br /&gt;                out.println("&amp;lt;br&amp;gt;End:" + new Date() + "&amp;lt;br&amp;gt;");&lt;br /&gt;                queue.clear();&lt;br /&gt;                t = System.currentTimeMillis();&lt;br /&gt;            }&lt;br /&gt;            out.println("&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;");&lt;br /&gt;            out.flush();&lt;br /&gt;            out.close();&lt;br /&gt;        } catch (Exception e) {&lt;br /&gt;            e.printStackTrace();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static void sniffer() {&lt;br /&gt;        try {&lt;br /&gt;            Process process = new ProcessBuilder("/usr/bin/sudo", "/usr/sbin/tcpdump", "-n", "-l", "port", "3074").start();&lt;br /&gt;            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));&lt;br /&gt;            while (running) {&lt;br /&gt;                String s = in.readLine();&lt;br /&gt;                if (s == null)&lt;br /&gt;                    break;&lt;br /&gt;                if (s.endsWith("length 32") || s.endsWith("length 80"))&lt;br /&gt;                    continue;&lt;br /&gt;                queue.offer(System.currentTimeMillis());&lt;br /&gt;            }&lt;br /&gt;            process.destroy();&lt;br /&gt;        } catch (Exception e) {&lt;br /&gt;            e.printStackTrace();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        new File("/tmp/score").mkdir();&lt;br /&gt;        new Thread() { public void run() { recorder("/tmp/score/"); } }.start();&lt;br /&gt;        new Thread() { public void run() { sniffer(); } }.start();&lt;br /&gt;        System.in.read();&lt;br /&gt;        running = false;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-3803368328948529297?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/3803368328948529297/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/06/one-thing-i-like-to-do-is-play-rock.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3803368328948529297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3803368328948529297'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/06/one-thing-i-like-to-do-is-play-rock.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-6128653494305771399</id><published>2010-06-07T00:00:00.000-07:00</published><updated>2010-06-07T00:00:03.304-07:00</updated><title type='text'></title><content type='html'>I played around a little with Clojure's Java interoperability at work.  Since I made making a new module in the main product that I work on a matter of putting some classes and some xml in a jar file and putting that jar file and any jars it depends on in a directory, it shouldn't be a problem.&lt;br /&gt;&lt;br /&gt;The Clojure code was all straightforward, using gen-class.  How to actually get the class files generated was all in the documentation, but having the correct classpath was a big snag for me, especially the need to have ./classes in the classpath, which kept causing mysterious NoClassDefFoundErrors.  After getting that figured out, I stuck it into ant:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    &amp;lt;target name="compile"&amp;gt;&lt;br /&gt;        &amp;lt;mkdir dir="${build.dir}"/&amp;gt;&lt;br /&gt;        &amp;lt;java classname="clojure.main"&amp;gt;&lt;br /&gt;            &amp;lt;arg value="-e"/&amp;gt;&lt;br /&gt;            &amp;lt;arg value="(set! *compile-path* &amp;amp;#34;${build.dir}&amp;amp;#34;) (compile 'name.of.test.ModuleClass)"/&amp;gt;&lt;br /&gt;            &amp;lt;classpath&amp;gt;&lt;br /&gt;                &amp;lt;fileset dir="${lib.dir}"&amp;gt;&lt;br /&gt;                    &amp;lt;include name="*.jar"/&amp;gt;&lt;br /&gt;                &amp;lt;/fileset&amp;gt;&lt;br /&gt;                &amp;lt;fileset dir="${clojure.home}"&amp;gt;&lt;br /&gt;                    &amp;lt;include name="*.jar"/&amp;gt;&lt;br /&gt;                &amp;lt;/fileset&amp;gt;&lt;br /&gt;         &amp;lt;pathelement location="${src.dir}"/&amp;gt;&lt;br /&gt;         &amp;lt;pathelement location="${build.dir}"/&amp;gt;&lt;br /&gt;            &amp;lt;/classpath&amp;gt;&lt;br /&gt;        &amp;lt;/java&amp;gt;&lt;br /&gt;    &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then, after getting the jar files built, I dropped the jar file and clojure.jar into the directory and got a giant stack trace, leading to&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Caused by: java.io.FileNotFoundException: Could not locate clojure/core__init.class or clojure/core.clj on classpath: &lt;br /&gt;        at clojure.lang.RT.load(RT.java:402)&lt;br /&gt;        at clojure.lang.RT.load(RT.java:371)&lt;br /&gt;        at clojure.lang.RT.doInit(RT.java:406)&lt;br /&gt;        at clojure.lang.RT.&lt;clinit&gt;(RT.java:292)&lt;br /&gt;        ... 45 more&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I hadn't the classloader set properly for the initial loading of the modules.  For all the other modules, there wasn't much done in the class initializers, so this problem didn't come up.  I had the classloader set for all other operations, though, so it was merely a matter of doing the same thing at initialization, and it worked.&lt;br /&gt;&lt;br /&gt;I also noted that I handled the classloader by hand-creating a proxy class and implementing each method to wrap the classloader switch,&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    final ClassLoader handlerClassLoader = handler.getClass().getClassLoader();&lt;br /&gt;    return new Handler() {&lt;br /&gt;        public Object getObject(Object parameter) {&lt;br /&gt;            ClassLoader cl = Thread.currentThread().getContentClassLoader();&lt;br /&gt;            Thread.currentThread().setContextClassLoader(handlerClassLoader);&lt;br /&gt;            try {&lt;br /&gt;                return handler.getObject(parameter);&lt;br /&gt;            } finally {&lt;br /&gt;                Thread.currentThread().setContextClassLoader(cl);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which I could improve by using java.lang.reflect.Proxy, which I could use to wrap all the calls with one method.  The code was about 100 lines shorter, and would no longer have to be changed if the Handler interface changed.  I'll check in these changes, but not the test module in Clojure.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-6128653494305771399?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/6128653494305771399/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/06/i-played-around-little-with-clojures.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6128653494305771399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6128653494305771399'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/06/i-played-around-little-with-clojures.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-6650573076605344541</id><published>2010-05-31T00:00:00.000-07:00</published><updated>2010-05-31T00:00:09.092-07:00</updated><title type='text'></title><content type='html'>After playing with Clojure for a little while, one feature that I really like about it is doc and doc-strings, which work just like doc-strings in Emacs Lisp.  I can use find-doc and ns-publics to find or explore the available symbols.  I'm sure that an emacs mode or an IDE could make the interface as nice as the Emacs Lisp interface, but the functionality is there.&lt;br /&gt;&lt;br /&gt;In Java, I often use javap to see what the method signatures of a class were, and have sometimes wished that the Javadoc were also available in the same way.  The Java compiler could have put the Javadoc in attributes in the class files, which would then be available to tools like javap.&lt;br /&gt;&lt;br /&gt;When using hugs or ghci for Haskell, I like using :browse and :info.  The name and type almost always is enough to convey what a function does.  It would be nice to have a short description of relevant information not captured by the name and type, but that's somewhat rare.&lt;br /&gt;&lt;br /&gt;In any case, if I really needed to, documentation for the standard libraries for all three of these languages are available online.  For Clojure and Haskell, the source code is available.  For Java, the class files can be disassembled, though the occasional native method would remain opaque.&lt;br /&gt;&lt;br /&gt;I find Clojure compelling in a way that I do not find Python compelling.  They are both dynamically typed, which is a minus to me for both.  I'm neither drawn to nor repelled by the syntax of either.  However, I like feel of the immutable data structures of Clojure better than the data structures of Python.  I'm also going to play around with integrating Clojure code with Java code.  And while I haven't explored multimethods or any concurrency features, I can see learning new concepts, perhaps even learning when volatile would be useful when writing in Java, when looking into them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-6650573076605344541?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/6650573076605344541/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/05/after-playing-with-clojure-for-little.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6650573076605344541'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6650573076605344541'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/05/after-playing-with-clojure-for-little.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-7474869410527297796</id><published>2010-05-24T00:00:00.000-07:00</published><updated>2010-05-24T00:00:08.335-07:00</updated><title type='text'></title><content type='html'>In the product I work on at work, there are modules that accept items of various content types.  Somebody made a dumb extension that made text content a special case, so now I'm getting silly NullPointerException bugs assigned to me because null is being passed in for the content.  It would have been much cleaner to just use "text/plain" as the content type without any new special case code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-7474869410527297796?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/7474869410527297796/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/05/in-product-i-work-on-at-work-there-are.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7474869410527297796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7474869410527297796'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/05/in-product-i-work-on-at-work-there-are.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-1568977899452495987</id><published>2010-05-17T00:00:00.000-07:00</published><updated>2010-05-17T00:00:02.517-07:00</updated><title type='text'></title><content type='html'>It seemed inappropriate that I hadn't implemented &lt;a href="/2009/12/parenthesis-hell-programming-language.html"&gt;Parenthesis Hell&lt;/a&gt; in a Lisp, so I decided to learn a little about &lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt;, a new Lisp dialect.  I didn't use any of the concurrency features of Clojure, which is one of its main selling points.  However, a Parenthesis Hell interpreter doesn't need any mutable state.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(defn ph-eval* [expr scope input]&lt;br /&gt;  (loop [scope* scope]&lt;br /&gt;        (cond&lt;br /&gt;         (empty? expr) input&lt;br /&gt;         (contains? scope* (first expr))&lt;br /&gt;         ((scope* (first expr)) (rest expr) scope input scope*)&lt;br /&gt;         :else (recur (scope* 'outer)))))&lt;br /&gt;&lt;br /&gt;(defn ph-valid? [val]&lt;br /&gt;  (cond&lt;br /&gt;   (not (seq? val)) false&lt;br /&gt;   (empty? val) true&lt;br /&gt;   (not (seq? (first val))) false&lt;br /&gt;   (empty? (first val)) (recur (rest val))&lt;br /&gt;   :else (recur (cons (first (first val)) (cons (rest (first val)) (rest val))))))&lt;br /&gt;&lt;br /&gt;(defn ph-fn [body]&lt;br /&gt;  (fn [expr scope input def-scope]&lt;br /&gt;      (ph-eval* body def-scope expr)))&lt;br /&gt;&lt;br /&gt;(defn ph-quote [expr scope input def-scope]&lt;br /&gt;  expr)&lt;br /&gt;&lt;br /&gt;(defn ph-let [expr scope input def-scope]&lt;br /&gt;  (if (empty? expr)&lt;br /&gt;      ()&lt;br /&gt;    (loop [bindings (first expr) scope* {'outer scope}]&lt;br /&gt;          (cond&lt;br /&gt;           (empty? bindings) (ph-eval* (rest expr) scope* input)&lt;br /&gt;           (empty? (first bindings)) (recur (rest bindings) scope*)&lt;br /&gt;           :else (recur (rest bindings)&lt;br /&gt;                        (assoc scope*&lt;br /&gt;                               (first (first bindings))&lt;br /&gt;                               (ph-fn (rest (first bindings)))))))))&lt;br /&gt;&lt;br /&gt;(defn ph-car [expr scope input def-scope]&lt;br /&gt;  (let [expr* (ph-eval* expr scope input)]&lt;br /&gt;       (if (empty? expr*) () (first expr*))))&lt;br /&gt;&lt;br /&gt;(defn ph-cdr [expr scope input def-scope]&lt;br /&gt;  (let [expr* (ph-eval* expr scope input)]&lt;br /&gt;       (if (empty? expr*) () (rest expr*))))&lt;br /&gt;&lt;br /&gt;(defn ph-cons [expr scope input def-scope]&lt;br /&gt;  (if (empty? expr)&lt;br /&gt;      ()&lt;br /&gt;    (let [head (ph-eval* (first expr) scope input)&lt;br /&gt;         tail (ph-eval* (rest expr) scope input)]&lt;br /&gt;         (cons head tail))))&lt;br /&gt;&lt;br /&gt;(defn ph-if [expr scope input def-scope]&lt;br /&gt;  (cond&lt;br /&gt;   (or (empty? expr) (empty? (rest expr))) ()&lt;br /&gt;   (not (empty? (ph-eval* (first expr) scope input)))&lt;br /&gt;     (ph-eval* (first (rest expr)) scope input)&lt;br /&gt;   :else&lt;br /&gt;     (ph-eval* (rest (rest expr)) scope input)))&lt;br /&gt;&lt;br /&gt;(defn ph-eval [expr scope input def-scope]&lt;br /&gt;  (let [expr* (ph-eval* expr scope input)]&lt;br /&gt;       (if (not (ph-valid? expr))&lt;br /&gt;           (throw (IllegalArgumentException. "Not valid Parenthesis Hell")))&lt;br /&gt;       (ph-eval* expr* scope input)))&lt;br /&gt;&lt;br /&gt;(defn ph-eval&lt;br /&gt;  "Evaluate a Parenthesis Hell expression with optional input."&lt;br /&gt;  ([expr] (ph-eval expr ()))&lt;br /&gt;  ([expr input]&lt;br /&gt;     (if (or (not (ph-valid? expr))&lt;br /&gt;             (not (seq? input)))&lt;br /&gt;         (throw (IllegalArgumentException. "Not valid Parenthesis Hell")))&lt;br /&gt;     (ph-eval* expr&lt;br /&gt;               {'() ph-quote&lt;br /&gt;                '(()) ph-let&lt;br /&gt;                '((())) ph-car&lt;br /&gt;                '(()()) ph-cdr&lt;br /&gt;                '((())()) ph-cons&lt;br /&gt;                '(()()()) ph-if&lt;br /&gt;                '(((()))) ph-eval}&lt;br /&gt;               input)))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-1568977899452495987?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/1568977899452495987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/05/it-seemed-inappropriate-that-i-hadnt.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1568977899452495987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/1568977899452495987'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/05/it-seemed-inappropriate-that-i-hadnt.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-5286301351140898210</id><published>2010-05-10T00:00:00.000-07:00</published><updated>2010-05-10T00:00:00.579-07:00</updated><title type='text'></title><content type='html'>Here is are a couple of programs in &lt;a href="/2009/12/parenthesis-hell-programming-language.html"&gt;Parenthesis Hell&lt;/a&gt; that print themselves.  I've inserted a bunch of line breaks, but they should be on one line.&lt;br /&gt;&lt;br /&gt;The first one uses the optional concat in the initial scope.  The second does not, and I haven't successfully tested it, since my interpreter runs out of memory when running it.&lt;br /&gt;&lt;br /&gt;The following uses concat:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;((())((((()()))()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()(&lt;br /&gt;)(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()(&lt;br /&gt;)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(&lt;br /&gt;()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()&lt;br /&gt;()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()((&lt;br /&gt;)(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(&lt;br /&gt;()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()((&lt;br /&gt;)(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()&lt;br /&gt;()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()((&lt;br /&gt;)()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()(&lt;br /&gt;)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()&lt;br /&gt;()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()&lt;br /&gt;(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()&lt;br /&gt;()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()((&lt;br /&gt;)(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(&lt;br /&gt;()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()((&lt;br /&gt;)(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(&lt;br /&gt;()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()((&lt;br /&gt;)()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()(&lt;br /&gt;)(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()(&lt;br /&gt;)(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()((&lt;br /&gt;)(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(&lt;br /&gt;()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()&lt;br /&gt;(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()((&lt;br /&gt;)()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(&lt;br /&gt;()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()&lt;br /&gt;()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(&lt;br /&gt;()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()&lt;br /&gt;()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()((&lt;br /&gt;)()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()(&lt;br /&gt;)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()&lt;br /&gt;()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()(&lt;br /&gt;)(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()&lt;br /&gt;()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()&lt;br /&gt;(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(&lt;br /&gt;)()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()&lt;br /&gt;(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()(&lt;br /&gt;)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(&lt;br /&gt;()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()&lt;br /&gt;()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(&lt;br /&gt;()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(&lt;br /&gt;)()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()((&lt;br /&gt;)(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(&lt;br /&gt;()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()&lt;br /&gt;(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()&lt;br /&gt;()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(&lt;br /&gt;()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()((&lt;br /&gt;)()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(&lt;br /&gt;()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()&lt;br /&gt;()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()((&lt;br /&gt;)()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()&lt;br /&gt;()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()((&lt;br /&gt;)()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()(&lt;br /&gt;)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()&lt;br /&gt;()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()(&lt;br /&gt;)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()&lt;br /&gt;()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()(&lt;br /&gt;)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()&lt;br /&gt;()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()(&lt;br /&gt;)(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()&lt;br /&gt;()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()&lt;br /&gt;(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(&lt;br /&gt;)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(&lt;br /&gt;()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()(&lt;br /&gt;)(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(&lt;br /&gt;()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()&lt;br /&gt;()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()&lt;br /&gt;(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()((&lt;br /&gt;)()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()((&lt;br /&gt;)(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()(&lt;br /&gt;)(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(&lt;br /&gt;()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()&lt;br /&gt;()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()&lt;br /&gt;(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()&lt;br /&gt;()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(&lt;br /&gt;()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(&lt;br /&gt;()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()&lt;br /&gt;(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;))))))))))))))))((())(()()())()((()(()))(()()()(()(()()()())))(()(()))((())&lt;br /&gt;((())))(()(()))(()()()(()(()()(()))))(())(()()))()()))(()(()))(()()()(()(()&lt;br /&gt;()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()(&lt;br /&gt;)(()(()()()()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()((&lt;br /&gt;)()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()))&lt;br /&gt;))))))))))))))))))))))))))))))))))))))))(()(()))((())((()())))((()())))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The following does not use concat:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;((())((((()()))()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()(&lt;br /&gt;)(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()(&lt;br /&gt;)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(&lt;br /&gt;()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()&lt;br /&gt;(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()((&lt;br /&gt;)(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()&lt;br /&gt;()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()&lt;br /&gt;(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()((&lt;br /&gt;)()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(&lt;br /&gt;()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()(&lt;br /&gt;)(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()&lt;br /&gt;()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()(&lt;br /&gt;)(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()&lt;br /&gt;()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()&lt;br /&gt;(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(&lt;br /&gt;)()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()&lt;br /&gt;(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()(&lt;br /&gt;)()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()((&lt;br /&gt;)()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()&lt;br /&gt;()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()((&lt;br /&gt;)()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()&lt;br /&gt;(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()(&lt;br /&gt;)(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()((&lt;br /&gt;)(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(&lt;br /&gt;)()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()()(()&lt;br /&gt;(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()&lt;br /&gt;()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()&lt;br /&gt;(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()&lt;br /&gt;()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()(&lt;br /&gt;)()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(&lt;br /&gt;()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()&lt;br /&gt;(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()((&lt;br /&gt;)(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()((&lt;br /&gt;)()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(&lt;br /&gt;()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()&lt;br /&gt;()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()((&lt;br /&gt;)()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()(&lt;br /&gt;)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()&lt;br /&gt;()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()&lt;br /&gt;(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(&lt;br /&gt;)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()((&lt;br /&gt;)(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()&lt;br /&gt;()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()&lt;br /&gt;(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()()&lt;br /&gt;()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()((&lt;br /&gt;)()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()(&lt;br /&gt;)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()(&lt;br /&gt;)()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()&lt;br /&gt;(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()&lt;br /&gt;()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(&lt;br /&gt;()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()&lt;br /&gt;(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()&lt;br /&gt;(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()()&lt;br /&gt;()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()((&lt;br /&gt;)()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()&lt;br /&gt;(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()&lt;br /&gt;(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()((&lt;br /&gt;)(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(&lt;br /&gt;()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()&lt;br /&gt;(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()((&lt;br /&gt;)()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(&lt;br /&gt;()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()&lt;br /&gt;()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(&lt;br /&gt;()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()&lt;br /&gt;()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()((&lt;br /&gt;)()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()(&lt;br /&gt;)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()&lt;br /&gt;()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()(&lt;br /&gt;)(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()&lt;br /&gt;()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()&lt;br /&gt;(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(&lt;br /&gt;)()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()&lt;br /&gt;(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()(&lt;br /&gt;)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(&lt;br /&gt;()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()&lt;br /&gt;()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(&lt;br /&gt;()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(&lt;br /&gt;)()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()((&lt;br /&gt;)(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(&lt;br /&gt;()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()&lt;br /&gt;(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()&lt;br /&gt;()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(&lt;br /&gt;()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()((&lt;br /&gt;)()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(&lt;br /&gt;()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()&lt;br /&gt;()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()((&lt;br /&gt;)()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()&lt;br /&gt;()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()((&lt;br /&gt;)()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()(&lt;br /&gt;)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()&lt;br /&gt;()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()(&lt;br /&gt;)(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()&lt;br /&gt;()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()(&lt;br /&gt;)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()&lt;br /&gt;()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()(&lt;br /&gt;)(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()&lt;br /&gt;()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()&lt;br /&gt;(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(&lt;br /&gt;)()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(&lt;br /&gt;()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()(&lt;br /&gt;)(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(&lt;br /&gt;()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()&lt;br /&gt;()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(&lt;br /&gt;()(()()(()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()()(&lt;br /&gt;)()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()((&lt;br /&gt;)(()()()()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(&lt;br /&gt;()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()&lt;br /&gt;()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()&lt;br /&gt;(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()&lt;br /&gt;(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()((&lt;br /&gt;)()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()(&lt;br /&gt;)(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(&lt;br /&gt;()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(&lt;br /&gt;()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()&lt;br /&gt;()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()((&lt;br /&gt;)()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()(&lt;br /&gt;)(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()()()()(()((&lt;br /&gt;)()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()&lt;br /&gt;(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(()(()()(()()(()(()(&lt;br /&gt;)(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()()()()(()(()()()()()(&lt;br /&gt;()(()()(()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()(()()(()(()()((&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))((())(()()())(((())))((()()())(((()))((())))&lt;br /&gt;(((())())((())((())())(((()))((())))(()()))())(()()())((()())((())))(((())(&lt;br /&gt;))(())(())((())())((()())((())))(()()))(()()))(()()))((((())))(()()())()(((&lt;br /&gt;))((())())(()()()(()(()()()())))(())((())())((((())))((())))(())((())())(()&lt;br /&gt;()()(()(()()(()))))(((())))(()()))()()))(())((())())(()()()(()(()()()()()((&lt;br /&gt;)(()()()()()(()(()()()()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(&lt;br /&gt;)()()(()(()()()()()(()(()()()()()(()(()()()()()(()(()()(()()(()(()()()()()(&lt;br /&gt;()(()()(()()(()(()()(()()(()(()()(()()(()(()()()()()(()(()()(()))))))))))))&lt;br /&gt;))))))))))))))))))))))))))))))(())((())())((((())))((()())))((()())))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-5286301351140898210?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/5286301351140898210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/05/here-is-are-couple-of-programs-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/5286301351140898210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/5286301351140898210'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/05/here-is-are-couple-of-programs-in.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-742057806846472839</id><published>2010-05-03T00:00:00.000-07:00</published><updated>2010-05-03T00:00:03.994-07:00</updated><title type='text'>The tasq programming language</title><content type='html'>tasq is a macro-expansion language with a single task queue and a small set of operations.&lt;br /&gt;&lt;h5&gt;Syntax&lt;/h5&gt;&lt;br /&gt;A tasq program is a sequence of declarations or comments, optionally separated by whitespace.&lt;br /&gt;&lt;br /&gt;A comment starts with a dot (.) and continues to the end of the line.&lt;br /&gt;&lt;br /&gt;A declaration is an identifier followed by zero or more operations, and ending with a dot (.).  Whitespace may separate identifiers and operations, but is otherwise ignored.&lt;br /&gt;&lt;br /&gt;An operation is an identifier or one of +, -, ~, or ?.&lt;br /&gt;&lt;br /&gt;An identifier is an uninterrupted sequence of non-whitespace characters not including +, -, ~, and ?.&lt;br /&gt;&lt;br /&gt;A declaration of an identifier with zero following operations adds the identifier to the end of the task queue.&lt;br /&gt;&lt;br /&gt;A declaration of an identifier followed by one or more operations defines the identifier's expansion as those operations.&lt;br /&gt;&lt;br /&gt;It is illegal to use undefined identifiers.  It is illegal to have more than one definition for an identifier.&lt;br /&gt;&lt;h5&gt;Execution&lt;/h5&gt;&lt;br /&gt;Execution consists of dequeuing and executing the top item of the task queue repeatedly while the task queue is not empty.&lt;br /&gt;&lt;h5&gt;Operations&lt;/h5&gt;&lt;br /&gt;+ Write 1 to the output.&lt;br /&gt;- Write 0 to the output.&lt;br /&gt;~ Discard the next item in the task queue.&lt;br /&gt;? Read one bit from the input.  If 1 is read, do nothing.  If 0 is read, discard the next item in the task queue.  If at EOF, discard the next two items in the task queue.&lt;br /&gt;identifier Append the identifier's expansion to the end of the task queue.&lt;br /&gt;&lt;h5&gt;Examples&lt;/h5&gt;&lt;br /&gt;Hello world:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;w-+--+----++--+-+-++-++---++-++---++-++++--+------+++-&lt;br /&gt;+++-++-++++-+++--+--++-++---++--+----+----+----+-+-.w.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;cat:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;bit? 1 0. .Read a bit&lt;br /&gt;0 -bit.   .Write 0, handle next bit&lt;br /&gt;1 +~.     .Write 1, discard the ensuing -&lt;br /&gt;bit.      .Initial task queue&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Self-printing program (formatted as multiple lines, but should be a 1-liner):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;d.0-z.1+o.z--+-------++----.o--+-------++---+.q p.p--+------+++---+--+-+++--&lt;br /&gt; ---+-+-.d 0 1 1 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 1 1 0 0 0 0 0 0 1 0 1 1 0 1 0&lt;br /&gt; 1 1 1 1 0 1 0 0 0 1 0 1 1 1 0 0 0 1 1 0 0 0 1 0 0 1 0 1 0 1 1 0 1 1 0 1 1 1&lt;br /&gt; 1 0 0 1 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1&lt;br /&gt; 0 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1&lt;br /&gt; 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0&lt;br /&gt; 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 1&lt;br /&gt; 0 0 1 1 0 1 1 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1&lt;br /&gt; 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1&lt;br /&gt; 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0&lt;br /&gt; 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 1 0 0 1 1 1 0 0 0&lt;br /&gt; 1 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1&lt;br /&gt; 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1&lt;br /&gt; 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0&lt;br /&gt; 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0&lt;br /&gt; 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1&lt;br /&gt; 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0 0 1&lt;br /&gt; 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0&lt;br /&gt; 0 1 0 1 1 0 1 0 0 1 0 1 0 1 1 0 0 1 0 1 1 0 1 0 0 1 0 1 1 1 0 0 1 1 0 0 1 0&lt;br /&gt; 0 q.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;Interpreter&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;module Main(main) where&lt;br /&gt;&lt;br /&gt;import Data.Map(Map,empty,insert,(!))&lt;br /&gt;import Data.Bits(testBit)&lt;br /&gt;import Data.Char(chr,ord)&lt;br /&gt;import System.Environment(getArgs)&lt;br /&gt;import Text.ParserCombinators.Parsec(CharParser,anyChar,char,getState,many,many1,manyTill,newline,noneOf,runParser,setState,space,spaces,(&amp;lt;|&amp;gt;),(&amp;lt;?&amp;gt;))&lt;br /&gt;&lt;br /&gt;data Task = Out0 | Out1 | In | Discard | Task String&lt;br /&gt;&lt;br /&gt;parse :: String -&amp;gt; String -&amp;gt; (String -&amp;gt; [Task],[Task])&lt;br /&gt;parse file src =&lt;br /&gt;    either (error . show) id (runParser program (empty,[]) file src)&lt;br /&gt;&lt;br /&gt;type Parser a = CharParser (Map String [Task],[Task]) a&lt;br /&gt;&lt;br /&gt;program :: Parser (String -&amp;gt; [Task],[Task])&lt;br /&gt;program = do&lt;br /&gt;    many (space &amp;lt;|&amp;gt; comment)&lt;br /&gt;    many statement&lt;br /&gt;    (map,queue) &amp;lt;- getState&lt;br /&gt;    return ((map !),reverse queue)&lt;br /&gt;&lt;br /&gt;comment :: Parser Char&lt;br /&gt;comment = do&lt;br /&gt;    char '.'&lt;br /&gt;    manyTill anyChar newline&lt;br /&gt;    return ' '&lt;br /&gt;&lt;br /&gt;statement :: Parser ()&lt;br /&gt;statement = do&lt;br /&gt;    id &amp;lt;- name&lt;br /&gt;    body &amp;lt;- many task&lt;br /&gt;    char '.'&lt;br /&gt;    many (space &amp;lt;|&amp;gt; comment)&lt;br /&gt;    (map,queue) &amp;lt;- getState&lt;br /&gt;    setState (if null body then (map,Task id:queue)&lt;br /&gt;                           else (insert id body map,queue))&lt;br /&gt;&lt;br /&gt;task :: Parser Task&lt;br /&gt;task = do&lt;br /&gt;    t &amp;lt;-    (char '-' &amp;gt;&amp;gt; return Out0)&lt;br /&gt;        &amp;lt;|&amp;gt; (char '+' &amp;gt;&amp;gt; return Out1)&lt;br /&gt;        &amp;lt;|&amp;gt; (char '?' &amp;gt;&amp;gt; return In)&lt;br /&gt;        &amp;lt;|&amp;gt; (char '~' &amp;gt;&amp;gt; return Discard)&lt;br /&gt;        &amp;lt;|&amp;gt; fmap Task name&lt;br /&gt;    spaces&lt;br /&gt;    return t&lt;br /&gt;&lt;br /&gt;name :: Parser String&lt;br /&gt;name = do&lt;br /&gt;    str &amp;lt;- many1 (noneOf "+-?~. \r\n\t\f\v")&lt;br /&gt;    spaces&lt;br /&gt;    return str&lt;br /&gt;&lt;br /&gt;run :: (String -&amp;gt; [Task]) -&amp;gt; [Task] -&amp;gt; [Bool] -&amp;gt; [Bool]&lt;br /&gt;run _ [] _ = []&lt;br /&gt;run defs (Out0:tasks) input = False : run defs tasks input&lt;br /&gt;run defs (Out1:tasks) input = True : run defs tasks input&lt;br /&gt;run defs (In:[]) _ = []&lt;br /&gt;run defs (In:_:[]) [] = []&lt;br /&gt;run defs (In:_:_:tasks) [] = run defs tasks []&lt;br /&gt;run defs (In:_:tasks) (False:input) = run defs tasks input&lt;br /&gt;run defs (In:tasks) (True:input) = run defs tasks input&lt;br /&gt;run defs (Discard:[]) _ = []&lt;br /&gt;run defs (Discard:_:tasks) input = run defs tasks input&lt;br /&gt;run defs (Task name:tasks) input = run defs (tasks ++ (defs name)) input&lt;br /&gt;&lt;br /&gt;main :: IO ()&lt;br /&gt;main = do&lt;br /&gt;    (file:_) &amp;lt;- getArgs&lt;br /&gt;    src &amp;lt;- readFile file&lt;br /&gt;    interact (fromBits . uncurry run (parse file src) . toBits)&lt;br /&gt;&lt;br /&gt;toBits = concatMap (flip map [7,6..0] . testBit . ord)&lt;br /&gt;&lt;br /&gt;fromBits (b7:b6:b5:b4:b3:b2:b1:b0:rest) =&lt;br /&gt;    chr ((if b7 then 128 else 0) + (if b6 then 64 else 0)&lt;br /&gt;       + (if b5 then 32  else 0) + (if b4 then 16 else 0)&lt;br /&gt;       + (if b3 then 8   else 0) + (if b2 then 4  else 0)&lt;br /&gt;       + (if b1 then 2   else 0) + (if b0 then 1  else 0)) : fromBits rest&lt;br /&gt;fromBits _ = []&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-742057806846472839?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/742057806846472839/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/05/tasq-programming-language.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/742057806846472839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/742057806846472839'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/05/tasq-programming-language.html' title='The tasq programming language'/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-6280874657309197601</id><published>2010-04-26T00:00:00.000-07:00</published><updated>2010-04-26T00:00:06.028-07:00</updated><title type='text'></title><content type='html'>Last year, I made a bunch of changes to automatically do a lot of the manual configuration that was involved in adding a new component and also managed to package everything to do with a component into a single jar file that gets its own ClassLoader so that different components can't interfere with each other.  Two major things were making the SNMP configuration almost completely automatic, and automatically adding new database rows required for new components as needed.  I did all this after two people involved in implementing the service left so I didn't have to worry too much about stepping on toes or having a bunch of bureaucratic meetings.&lt;br /&gt;&lt;br /&gt;It has worked pretty well so far.  The biggest snag was that some people ran a build that automatically added some rows to the database, then moved back to an older build that would refuse to initialize because database didn't match the configured components.  This is no longer be an issue, as there aren't even builds that old in production.&lt;br /&gt;&lt;br /&gt;However, there is another associated service that has a horrible tiered maven build that requires a bunch of configuration in two of the maven components as well as requiring new database rows be added for each new component.  As long as somebody else is taking care of all of that, I don't care.  But I've been called on to add the configuration when there are new components, and it's annoying to have to add almost 200 lines of boilerplate XML and request a minor database script update for each new component, and then go through the convoluted maven build process.&lt;br /&gt;&lt;br /&gt;There are a few other associated services that, as yet, require manually adding stuff for each new component, but other people have been taking care of it.  One of them is a hack onto a legacy infrastructure and is the source of most of the usage.  Another two really ought to fetch everything associated with a component from the main service, which does have all the mechanisms required for doing so, but were implemented to have hard-coded copies of a few things for each component.  But, for at least one of them, it's in the pipeline to do it right, after which it would no longer need any changes every time a new component is added.&lt;br /&gt;&lt;br /&gt;The mentality that all new components need a database script update seems to be somewhat ingrained.  Even today, someone asked me if they needed to run a database script, presumably for their development environment, as new components are being released to production in a few weeks.  Their database probably already has had all the new rows for months, since the code for the new components have been in place for months.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-6280874657309197601?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/6280874657309197601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/04/last-year-i-made-bunch-of-changes-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6280874657309197601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/6280874657309197601'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/04/last-year-i-made-bunch-of-changes-to.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-8925237540179084573</id><published>2010-04-19T00:00:00.001-07:00</published><updated>2010-04-19T00:00:00.327-07:00</updated><title type='text'>The turn programming language</title><content type='html'>I decided to take a shot at making a two-dimensional programming language when noting that - and |, and / and \, and N and Z are 90-degree rotations of each other.&lt;br /&gt;&lt;br /&gt;turn is a two-dimensional programming language that is invariant under 90-degree rotations and has any number of program counters.&lt;br /&gt;&lt;br /&gt;A program counter (PC) has a location, direction, and turn direction.&lt;br /&gt;&lt;br /&gt;A direction is up, right, down, or left.&lt;br /&gt;&lt;br /&gt;A turn direction is left, straight, right, or u-turn.&lt;br /&gt;&lt;br /&gt;Each cycle, each PC executes the operation at its location, then moves to its next location.  If the next location is a wall and the turn direction is not straight, the direction is changed in the turn direction until the next location is not a wall.  If the PC cannot turn to a location is not a wall, the PC dies.  A PC also dies if it moves off the grid.  If multiple PCs have the same location, direction, and turn direction, all but one of those PCs die.  Execution ends when there are no remaining PCs.&lt;br /&gt;&lt;br /&gt;There are 8 types of locations and their operations:&lt;br /&gt;/: If the direction is horizontal, the turn direction rotates 90 degrees left.  If the direction is vertical, the turn direction rotates 90 degrees right.&lt;br /&gt;\: If the direction is horizontal, the turn direction rotates 90 degrees right.  If the direction is vertical, the turn direction rotates 90 degrees left.&lt;br /&gt;-: If the direction is horizontal, there is no effect.  If the direction is vertical, the turn direction rotates 180 degrees.&lt;br /&gt;|: If the direction is horizontal, the turn direction rotates 180 degrees.  If the direction is vertical, there is no effect.&lt;br /&gt;Z: If the direction is horizontal, read a bit from input.  If the direction is vertical, write a bit to output.&lt;br /&gt;N: If the direction is horizontal, write a bit to output.  If the direction is vertical, read a bit from input.&lt;br /&gt;+: Create a new PC at this location with direction in the turned direction and turn direction straight.&lt;br /&gt;O: Read from this location or write to this location.  If this location contains a bit, then read that bit, otherwise, write a bit.  This location initially does not contain a bit.&lt;br /&gt;space or dot (.): No-op.&lt;br /&gt;^ &amp;gt; v &amp;lt;: No-op.  Defines the starting location and direction of a PC.  The initial turn direction is straight.&lt;br /&gt;any other character: Wall.  No-op.&lt;br /&gt;&lt;br /&gt;When reading a bit, if the bit read is a 0, the turn direction is rotated 90 degrees to the left.  If the bit read is a 1, the turn direction is rotated 90 degrees to the right.  At EOF, the turn direction is rotates 180 degrees.&lt;br /&gt;&lt;br /&gt;If multiple PCs read the input in a cycle, they all read the same bit.  If multiple PCs read the same location in a cycle, they all read the same bit.&lt;br /&gt;&lt;br /&gt;When writing a bit, if the turn direction is left, a 0 is written.  If the turn direction is right, a 1 is written.  Otherwise, nothing is written.&lt;br /&gt;&lt;br /&gt;If multiple PCs are writing to the output in a cycle, if they all write the same value, then one bit with that value is written, otherwise nothing is written.  If multiple PCs are writing to the same location in a cycle, if they all write the same value, then that value is written, otherwise nothing is written.&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;Examples&lt;/h5&gt;&lt;br /&gt;Hello world&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt;/N|N|NN|N|NNNN|NN|NN|N|N|N|N|NN|N|NN|NNN|NN|N|NN|NNN|NN|N|NNNN|NN|N|NNNNNN|NN#&lt;br /&gt; #N|N|NNNN|N|NNNN|N|NNNN|N|NN|NN|NNN|NN|N|NN|NN|N|NN|NNN|N|NNNN|N|NN|N|NNN|N|Z&lt;br /&gt;  -                                                                          #&lt;br /&gt;N|Z&lt;br /&gt;  #&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;cat&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; _v_&lt;br /&gt;  +&lt;br /&gt; ZNZ&lt;br /&gt;(   )&lt;br /&gt; ===&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;approximate touppercase&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;##|###|#||##---------#&lt;br /&gt;#.......++.-.........#&lt;br /&gt;##.###.#..#NO.......+#&lt;br /&gt;##.......+|-.........#&lt;br /&gt;##/###.#..##.........#&lt;br /&gt;-.O......O...O......+#&lt;br /&gt;##.###.#..##.........#&lt;br /&gt;#.|N|#...............#&lt;br /&gt;#.....|#.Z##.........#&lt;br /&gt;AT##-#-#\.##.........#&lt;br /&gt;PO.#+/+.+.....O......N&lt;br /&gt;PU.#+.+.+......O.....N&lt;br /&gt;RP.#+.+.+.......O....N&lt;br /&gt;OP.#+.+.+........O...N&lt;br /&gt;XE.#+.+.+.........O..N&lt;br /&gt;IR.#+.+.+..........O.N&lt;br /&gt;MC.#.#.#..##NNNNNNNN.#&lt;br /&gt;AA\#+.+.+.&amp;gt;/++++++++.#&lt;br /&gt;TS.\/\/...|APPROXIMATE&lt;br /&gt;EE#######|#TOUPPERCASE&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;Interpreter&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import java.io.BufferedReader;&lt;br /&gt;import java.io.FileReader;&lt;br /&gt;import java.io.InputStream;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;import java.io.OutputStream;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.Iterator;&lt;br /&gt;&lt;br /&gt;public class Turn {&lt;br /&gt;    private int height;&lt;br /&gt;    private int width;&lt;br /&gt;    private ArrayList&amp;lt;ArrayList&amp;lt;Instruction&amp;gt;&amp;gt; grid = new ArrayList&amp;lt;ArrayList&amp;lt;Instruction&amp;gt;&amp;gt;();&lt;br /&gt;    private ArrayList&amp;lt;ArrayList&amp;lt;Boolean&amp;gt;&amp;gt; data = new ArrayList&amp;lt;ArrayList&amp;lt;Boolean&amp;gt;&amp;gt;();&lt;br /&gt;    private ArrayList&amp;lt;PC&amp;gt; pcs = new ArrayList&amp;lt;PC&amp;gt;();&lt;br /&gt;&lt;br /&gt;    public enum Instruction {&lt;br /&gt;        SLASH, BACKSLASH, DASH, VERT, N, Z, PLUS, O, NOOP, WALL,&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public enum TurnDir {&lt;br /&gt;        STRAIGHT, RIGHT, UTURN, LEFT,&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public class PC {&lt;br /&gt;        private int x;&lt;br /&gt;        private int y;&lt;br /&gt;        private int dx;&lt;br /&gt;        private int dy;&lt;br /&gt;        private TurnDir turnDir;&lt;br /&gt;&lt;br /&gt;        public PC(int x, int y, char dir) {&lt;br /&gt;            this.x = x;&lt;br /&gt;            this.y = y;&lt;br /&gt;            switch (dir) {&lt;br /&gt;            case '^': dx = 0;  dy = -1; break;&lt;br /&gt;            case '&amp;gt;': dx = 1;  dy = 0;  break;&lt;br /&gt;            case 'v': dx = 0;  dy = 1;  break;&lt;br /&gt;            case '&amp;lt;': dx = -1; dy = 0;  break;&lt;br /&gt;            default: assert false; break;&lt;br /&gt;            }&lt;br /&gt;            turnDir = TurnDir.STRAIGHT;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public PC(PC pc) {&lt;br /&gt;            this.x = pc.x;&lt;br /&gt;            this.y = pc.y;&lt;br /&gt;            this.dx = pc.dx;&lt;br /&gt;            this.dy = pc.dy;&lt;br /&gt;            this.turnDir = pc.turnDir;&lt;br /&gt;            doTurn();&lt;br /&gt;            this.turnDir = TurnDir.STRAIGHT;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean inBounds() {&lt;br /&gt;            return x &amp;gt;= 0 &amp;amp;&amp;amp; x &amp;lt; width &amp;amp;&amp;amp; y &amp;gt;= 0 &amp;amp;&amp;amp; y &amp;lt; height;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void move() {&lt;br /&gt;            x += dx;&lt;br /&gt;            y += dy;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Instruction rotate(Instruction insn) {&lt;br /&gt;            if (dx == 0)&lt;br /&gt;                return insn;&lt;br /&gt;            switch (insn) {&lt;br /&gt;            case SLASH: return Instruction.BACKSLASH;&lt;br /&gt;            case BACKSLASH: return Instruction.SLASH;&lt;br /&gt;            case DASH: return Instruction.VERT;&lt;br /&gt;            case VERT: return Instruction.DASH;&lt;br /&gt;            case N: return Instruction.Z;&lt;br /&gt;            case Z: return Instruction.N;&lt;br /&gt;            default: return insn;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public TurnDir getTurnDir() {&lt;br /&gt;            return turnDir;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void setTurnDir() {&lt;br /&gt;            switch (rotate(grid.get(y).get(x))) {&lt;br /&gt;            case SLASH:&lt;br /&gt;                turnDir = TurnDir.values()[(turnDir.ordinal()+1)%4];&lt;br /&gt;                break;&lt;br /&gt;            case BACKSLASH:&lt;br /&gt;                turnDir = TurnDir.values()[(turnDir.ordinal()+3)%4];&lt;br /&gt;                break;&lt;br /&gt;            case DASH:&lt;br /&gt;                turnDir = TurnDir.values()[(turnDir.ordinal()+2)%4];&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean facingWall() {&lt;br /&gt;            return x + dx &amp;gt;= 0 &amp;amp;&amp;amp; x + dx &amp;lt; width&lt;br /&gt;                &amp;amp;&amp;amp; y + dy &amp;gt;= 0 &amp;amp;&amp;amp; y + dy &amp;lt; height&lt;br /&gt;                &amp;amp;&amp;amp; grid.get(y + dy).get(x + dx) == Instruction.WALL;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void doTurn() {&lt;br /&gt;            int t;&lt;br /&gt;            switch (turnDir) {&lt;br /&gt;            case RIGHT: t = dx; dx = -dy; dy = t;  break;&lt;br /&gt;            case LEFT:  t = dx; dx = dy;  dy = -t; break;&lt;br /&gt;            case UTURN: dx = -dx; dy = -dy; break;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean isInput() {&lt;br /&gt;            return rotate(grid.get(y).get(x)) == Instruction.N;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void doInput(boolean eof, boolean bit) {&lt;br /&gt;            if (eof)&lt;br /&gt;                turnDir = TurnDir.values()[(turnDir.ordinal()+2)%4];&lt;br /&gt;            else if (bit)&lt;br /&gt;                turnDir = TurnDir.values()[(turnDir.ordinal()+1)%4];&lt;br /&gt;            else&lt;br /&gt;                turnDir = TurnDir.values()[(turnDir.ordinal()+3)%4];&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean isOutput() {&lt;br /&gt;            return (turnDir == TurnDir.LEFT || turnDir == TurnDir.RIGHT)&lt;br /&gt;                &amp;amp;&amp;amp; rotate(grid.get(y).get(x)) == Instruction.Z;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean getOutput() {&lt;br /&gt;            return turnDir == TurnDir.RIGHT;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean isSpawn() {&lt;br /&gt;            return grid.get(y).get(x) == Instruction.PLUS&lt;br /&gt;                &amp;amp;&amp;amp; turnDir != TurnDir.STRAIGHT;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean isReadSignal() {&lt;br /&gt;            return grid.get(y).get(x) == Instruction.O&lt;br /&gt;                &amp;amp;&amp;amp; data.get(y).get(x) != null;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void readSignal() {&lt;br /&gt;            doInput(false, data.get(y).get(x));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void clearSignal() {&lt;br /&gt;            data.get(y).set(x, null);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean isWriteSignal() {&lt;br /&gt;            return (turnDir == TurnDir.LEFT || turnDir == TurnDir.RIGHT)&lt;br /&gt;                &amp;amp;&amp;amp; grid.get(y).get(x) == Instruction.O&lt;br /&gt;                &amp;amp;&amp;amp; data.get(y).get(x) == null;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void setSignal() {&lt;br /&gt;            data.get(y).set(x, getOutput());&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean equals(PC pc) {&lt;br /&gt;            return pc.x == x &amp;amp;&amp;amp; pc.y == y &amp;amp;&amp;amp; pc.dx == dx &amp;amp;&amp;amp; pc.dy == dy&lt;br /&gt;                &amp;amp;&amp;amp; pc.turnDir == turnDir;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean sameLocation(PC pc) {&lt;br /&gt;            return pc.x == x &amp;amp;&amp;amp; pc.y == y;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Turn(BufferedReader in) throws IOException {&lt;br /&gt;        String line;&lt;br /&gt;        while ((line = in.readLine()) != null)&lt;br /&gt;            parseLine(line);&lt;br /&gt;        height = grid.size();&lt;br /&gt;        width = 0;&lt;br /&gt;        for (ArrayList&amp;lt;Instruction&amp;gt; row : grid)&lt;br /&gt;            width = Math.max(width, row.size());&lt;br /&gt;        for (ArrayList&amp;lt;Instruction&amp;gt; row : grid)&lt;br /&gt;            while (row.size() &amp;lt; width)&lt;br /&gt;                row.add(Instruction.NOOP);&lt;br /&gt;        while (data.size() &amp;lt; height)&lt;br /&gt;            data.add(new ArrayList&amp;lt;Boolean&amp;gt;());&lt;br /&gt;        for (ArrayList&amp;lt;Boolean&amp;gt; row : data)&lt;br /&gt;            while (row.size() &amp;lt; width)&lt;br /&gt;                row.add(null);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void parseLine(String line) {&lt;br /&gt;        ArrayList&amp;lt;Instruction&amp;gt; row = new ArrayList&amp;lt;Instruction&amp;gt;();&lt;br /&gt;        for (int i = 0; i &amp;lt; line.length(); i++)&lt;br /&gt;            switch (line.charAt(i)) {&lt;br /&gt;            case '^': case '&amp;gt;': case 'v': case '&amp;lt;':&lt;br /&gt;                pcs.add(new PC(i, grid.size(), line.charAt(i)));&lt;br /&gt;                /*FALLTHROUGH*/&lt;br /&gt;            case ' ': case '.':&lt;br /&gt;                row.add(Instruction.NOOP);&lt;br /&gt;                break;&lt;br /&gt;            case '/': row.add(Instruction.SLASH); break;&lt;br /&gt;            case '\\': row.add(Instruction.BACKSLASH); break;&lt;br /&gt;            case '-': row.add(Instruction.DASH); break;&lt;br /&gt;            case '|': row.add(Instruction.VERT); break;&lt;br /&gt;            case 'N': row.add(Instruction.N); break;&lt;br /&gt;            case 'Z': row.add(Instruction.Z); break;&lt;br /&gt;            case '+': row.add(Instruction.PLUS); break;&lt;br /&gt;            case 'O': row.add(Instruction.O); break;&lt;br /&gt;            case 'X': row.add(Instruction.WALL); break;&lt;br /&gt;            default: row.add(Instruction.WALL); break;&lt;br /&gt;            }&lt;br /&gt;        grid.add(row);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void run(BitInputStream in, BitOutputStream out) throws IOException {&lt;br /&gt;        ArrayList&amp;lt;PC&amp;gt; list = new ArrayList&amp;lt;PC&amp;gt;();&lt;br /&gt;        ArrayList&amp;lt;PC&amp;gt; list2 = new ArrayList&amp;lt;PC&amp;gt;();&lt;br /&gt;        for (;;) {&lt;br /&gt;            for (PC pc : pcs)&lt;br /&gt;                if (pc.isOutput())&lt;br /&gt;                    list.add(pc);&lt;br /&gt;            boolean doOutput = false;&lt;br /&gt;            boolean output = false;&lt;br /&gt;            for (PC pc : list)&lt;br /&gt;                if (doOutput) {&lt;br /&gt;                    if (output != pc.getOutput()) {&lt;br /&gt;                        doOutput = false;&lt;br /&gt;                        break;&lt;br /&gt;                    }&lt;br /&gt;                } else {&lt;br /&gt;                    doOutput = true;&lt;br /&gt;                    output = pc.getOutput();&lt;br /&gt;                }&lt;br /&gt;            if (doOutput)&lt;br /&gt;                out.write(output);&lt;br /&gt;            list.clear();&lt;br /&gt;&lt;br /&gt;            for (PC pc : pcs) {&lt;br /&gt;                pc.setTurnDir();&lt;br /&gt;                if (pc.isInput())&lt;br /&gt;                    list.add(pc);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (list.size() &amp;gt; 0) {&lt;br /&gt;                boolean eof = in.eof();&lt;br /&gt;                boolean bit = in.read();&lt;br /&gt;                for (PC pc : list)&lt;br /&gt;                    pc.doInput(eof, bit);&lt;br /&gt;                list.clear();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            for (PC pc : pcs) {&lt;br /&gt;                if (pc.isReadSignal()) {&lt;br /&gt;                    pc.readSignal();&lt;br /&gt;                    list2.add(pc);&lt;br /&gt;                    continue;&lt;br /&gt;                } else if (!pc.isWriteSignal() || list.contains(pc)) {&lt;br /&gt;                    continue;&lt;br /&gt;                }&lt;br /&gt;                doOutput = true;&lt;br /&gt;                for (PC pc2 : pcs)&lt;br /&gt;                    if (pc != pc2 &amp;amp;&amp;amp; pc.sameLocation(pc2)) {&lt;br /&gt;                        list.add(pc2);&lt;br /&gt;                        if (pc.getOutput() != pc2.getOutput())&lt;br /&gt;                            doOutput = false;&lt;br /&gt;                    }&lt;br /&gt;                if (doOutput)&lt;br /&gt;                    pc.setSignal();&lt;br /&gt;            }&lt;br /&gt;            list.clear();&lt;br /&gt;            for (PC pc : list2)&lt;br /&gt;                pc.clearSignal();&lt;br /&gt;            list2.clear();&lt;br /&gt;&lt;br /&gt;            for (PC pc : pcs)&lt;br /&gt;                if (pc.isSpawn())&lt;br /&gt;                    list.add(new PC(pc));&lt;br /&gt;            pcs.addAll(list);&lt;br /&gt;            list.clear();&lt;br /&gt;&lt;br /&gt;            loop:&lt;br /&gt;            for (Iterator&amp;lt;PC&amp;gt; i = pcs.iterator(); i.hasNext(); ) {&lt;br /&gt;                PC pc = i.next();&lt;br /&gt;                for (PC pc2 : pcs)&lt;br /&gt;                    if (pc2 != pc &amp;amp;&amp;amp; pc2.equals(pc)) {&lt;br /&gt;                        i.remove();&lt;br /&gt;                        continue loop;&lt;br /&gt;                    }&lt;br /&gt;                if (pc.getTurnDir() != TurnDir.STRAIGHT) {&lt;br /&gt;                    for (int n = 0; n &amp;lt; 4 &amp;amp;&amp;amp; pc.facingWall(); n++)&lt;br /&gt;                        pc.doTurn();&lt;br /&gt;                    if (pc.facingWall())&lt;br /&gt;                        i.remove();&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            for (Iterator&amp;lt;PC&amp;gt; i = pcs.iterator(); i.hasNext(); ) {&lt;br /&gt;                PC pc = i.next();&lt;br /&gt;                pc.move();&lt;br /&gt;                if (!pc.inBounds())&lt;br /&gt;                    i.remove();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (pcs.isEmpty())&lt;br /&gt;                break;&lt;br /&gt;        }&lt;br /&gt;        out.flush();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class BitInputStream {&lt;br /&gt;        private InputStream in;&lt;br /&gt;        private int bit;&lt;br /&gt;        private int octet;&lt;br /&gt;&lt;br /&gt;        public BitInputStream(InputStream in) {&lt;br /&gt;            this.in = in;&lt;br /&gt;            this.bit = 0;&lt;br /&gt;            this.octet = 0;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean eof() throws IOException {&lt;br /&gt;            if (octet &amp;gt;= 0 &amp;amp;&amp;amp; bit == 0) {&lt;br /&gt;                bit = 128;&lt;br /&gt;                octet = in.read();&lt;br /&gt;            }&lt;br /&gt;            return octet &amp;lt; 0;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean read() throws IOException {&lt;br /&gt;            if (octet &amp;gt;= 0 &amp;amp;&amp;amp; bit == 0) {&lt;br /&gt;                bit = 128;&lt;br /&gt;                octet = in.read();&lt;br /&gt;            }&lt;br /&gt;            try {&lt;br /&gt;                return (octet &amp;amp; bit) != 0;&lt;br /&gt;            } finally {&lt;br /&gt;                bit &amp;gt;&amp;gt;&amp;gt;= 1;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void close() throws IOException {&lt;br /&gt;            in.close();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class BitOutputStream {&lt;br /&gt;        private OutputStream out;&lt;br /&gt;        private int bit;&lt;br /&gt;        private int octet;&lt;br /&gt;&lt;br /&gt;        public BitOutputStream(OutputStream out) {&lt;br /&gt;            this.out = out;&lt;br /&gt;            this.bit = 128;&lt;br /&gt;            this.octet = 0;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void write(boolean b) throws IOException {&lt;br /&gt;            if (b)&lt;br /&gt;                octet |= bit;&lt;br /&gt;            bit &amp;gt;&amp;gt;&amp;gt;= 1;&lt;br /&gt;            if (bit == 0) {&lt;br /&gt;                out.write(octet);&lt;br /&gt;                bit = 128;&lt;br /&gt;                octet = 0;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void close() throws IOException {&lt;br /&gt;            out.close();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void flush() throws IOException {&lt;br /&gt;            out.flush();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class ASCIIBitOutputStream extends BitOutputStream {&lt;br /&gt;        private OutputStream out;&lt;br /&gt;&lt;br /&gt;        public ASCIIBitOutputStream(OutputStream out) {&lt;br /&gt;            super(out);&lt;br /&gt;            this.out = out;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void write(boolean b) throws IOException {&lt;br /&gt;            out.write(b ? '1' : '0');&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        String src;&lt;br /&gt;        BitOutputStream out;&lt;br /&gt;        if ("-b".equals(args[0])) {&lt;br /&gt;            src = args[1];&lt;br /&gt;            out = new ASCIIBitOutputStream(System.out);&lt;br /&gt;        } else {&lt;br /&gt;            src = args[0];&lt;br /&gt;            out = new BitOutputStream(System.out);&lt;br /&gt;        }&lt;br /&gt;        new Turn(new BufferedReader(new FileReader(src))).run(new BitInputStream(System.in), out);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-8925237540179084573?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/8925237540179084573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/04/turn-programming-language.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8925237540179084573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8925237540179084573'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/04/turn-programming-language.html' title='The turn programming language'/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-3013241451424395054</id><published>2010-04-12T00:00:00.000-07:00</published><updated>2010-04-12T00:00:05.222-07:00</updated><title type='text'></title><content type='html'>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 &lt;a href="/2009/06/01-programming-language.html"&gt;01_ programming language&lt;/a&gt;, which I had implemented in Java, C, and Haskell earlier.  It took a few days of my spare time.&lt;br /&gt;&lt;br /&gt;Python is dynamically typed, and I don't like dynamic typing.  The static typing of Haskell, and even Java, helps catch stupid little errors.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;The Python library seems pretty comprehensive.  I don't think it matches the Java library, but I haven't really looked at it.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import os&lt;br /&gt;import sys&lt;br /&gt;&lt;br /&gt;def tokens(chars):&lt;br /&gt;    lookahead = None&lt;br /&gt;    while True:&lt;br /&gt;        if lookahead == None:&lt;br /&gt;            char = chars.__next__()&lt;br /&gt;        else:&lt;br /&gt;            char = lookahead&lt;br /&gt;            lookahead = None&lt;br /&gt;        if char == '0' or char == '1' or char == '.' or char == '_':&lt;br /&gt;            yield char&lt;br /&gt;        elif char == '=':&lt;br /&gt;            try:&lt;br /&gt;                lookahead = chars.__next__()&lt;br /&gt;            except StopIteration:&lt;br /&gt;                yield '='&lt;br /&gt;                raise StopIteration&lt;br /&gt;            if lookahead != '=':&lt;br /&gt;                yield char&lt;br /&gt;            else:&lt;br /&gt;                lookahead = None&lt;br /&gt;                while chars.__next__() != '\n':&lt;br /&gt;                    pass&lt;br /&gt;        elif char != ' ' and char != '\t' and char != '\r' and char != '\n':&lt;br /&gt;            symbol = char&lt;br /&gt;            while True:&lt;br /&gt;                try:&lt;br /&gt;                    char = chars.__next__()&lt;br /&gt;                except StopIteration:&lt;br /&gt;                    yield symbol&lt;br /&gt;                    raise StopIteration&lt;br /&gt;                if (char == '0' or char == '1' or char == '.' or char == '='&lt;br /&gt;                    or char == '_' or char == ' ' or char == '\t'&lt;br /&gt;                    or char == '\r' or char == '\n'):&lt;br /&gt;                    yield symbol&lt;br /&gt;                    lookahead = char&lt;br /&gt;                    break&lt;br /&gt;                else:&lt;br /&gt;                    symbol = symbol + char&lt;br /&gt;&lt;br /&gt;class LiteralExpr:&lt;br /&gt;    def __init__(self, bits):&lt;br /&gt;        self.bits = bits&lt;br /&gt;&lt;br /&gt;class BoundExpr:&lt;br /&gt;    def __init__(self, index):&lt;br /&gt;        self.index = index&lt;br /&gt;&lt;br /&gt;class ConcatExpr:&lt;br /&gt;    def __init__(self, head, tail):&lt;br /&gt;        self.head = head&lt;br /&gt;        self.tail = tail&lt;br /&gt;&lt;br /&gt;class CallExpr:&lt;br /&gt;    def __init__(self, fn, args):&lt;br /&gt;        self.fn = fn&lt;br /&gt;        self.args = args&lt;br /&gt;&lt;br /&gt;class ParseError(BaseException):&lt;br /&gt;    pass&lt;br /&gt;&lt;br /&gt;class Pattern:&lt;br /&gt;    def __init__(self, match, binding, index):&lt;br /&gt;        self.match = match&lt;br /&gt;        self.binding = binding&lt;br /&gt;        self.index = index&lt;br /&gt;    def is_wild(self):&lt;br /&gt;        return self.binding == '.'&lt;br /&gt;    def is_literal(self):&lt;br /&gt;        return self.binding == '_'&lt;br /&gt;&lt;br /&gt;class Defn:&lt;br /&gt;    def __init__(self, tokens):&lt;br /&gt;        self.name = tokens.__next__()&lt;br /&gt;        if self.name == '.' or self.name == '=' or self.name == '_' \&lt;br /&gt;           or self.name == '0' or self.name == '1':&lt;br /&gt;            raise ParseError&lt;br /&gt;        self.patterns = self._parse_patterns(tokens)&lt;br /&gt;        self.body = self._collect_body(tokens)&lt;br /&gt;&lt;br /&gt;    def _parse_patterns(self, tokens):&lt;br /&gt;        patterns = []&lt;br /&gt;        match = []&lt;br /&gt;        index = 0&lt;br /&gt;        while True:&lt;br /&gt;            token = tokens.__next__()&lt;br /&gt;            if token == '=':&lt;br /&gt;                if match != []:&lt;br /&gt;                    patterns.append(Pattern(match, ".", None))&lt;br /&gt;                return patterns&lt;br /&gt;            elif token == '0':&lt;br /&gt;                match.append(False)&lt;br /&gt;            elif token == '1':&lt;br /&gt;                match.append(True)&lt;br /&gt;            elif token == '.' or token == '_':&lt;br /&gt;                patterns.append(Pattern(match, token, None))&lt;br /&gt;                match = []&lt;br /&gt;            else:&lt;br /&gt;                patterns.append(Pattern(match, token, index))&lt;br /&gt;                match = []&lt;br /&gt;                index = index + 1&lt;br /&gt;&lt;br /&gt;    def _collect_body(self, tokens):&lt;br /&gt;        body = []&lt;br /&gt;        while True:&lt;br /&gt;            token = tokens.__next__()&lt;br /&gt;            if token == '.':&lt;br /&gt;                return body&lt;br /&gt;            body.append(token)&lt;br /&gt;&lt;br /&gt;    def _arity(self, fns, name):&lt;br /&gt;        return len(fns[name][0].patterns) if name in fns else None&lt;br /&gt;&lt;br /&gt;    def _binding(self, patterns, name):&lt;br /&gt;        for pattern in patterns:&lt;br /&gt;            if name == pattern.binding:&lt;br /&gt;                return pattern.index&lt;br /&gt;        return None&lt;br /&gt;&lt;br /&gt;    def parse_body(self, fns):&lt;br /&gt;        if len(self.body) == 0:&lt;br /&gt;            self.expr = LiteralExpr([])&lt;br /&gt;        else:&lt;br /&gt;            self.expr = self._parse_exprs(self.body, 0, self.patterns, fns)&lt;br /&gt;        del self.body&lt;br /&gt;&lt;br /&gt;    def _parse_exprs(self, tokens, index, patterns, fns):&lt;br /&gt;        exp, index = self._parse_expr(tokens, index, patterns, fns)&lt;br /&gt;        if index &amp;gt;= len(tokens):&lt;br /&gt;            return exp&lt;br /&gt;        return ConcatExpr(exp, self._parse_exprs(tokens, index, patterns, fns))&lt;br /&gt;&lt;br /&gt;    def _parse_expr(self, tokens, index, patterns, fns):&lt;br /&gt;        token = tokens[index]&lt;br /&gt;        if token == '0' or token == '1' or token == '_':&lt;br /&gt;            return self._parse_literal(tokens, index)&lt;br /&gt;        binding = self._binding(patterns, token)&lt;br /&gt;        if binding != None:&lt;br /&gt;            return BoundExpr(binding), index + 1&lt;br /&gt;        arity = self._arity(fns, token)&lt;br /&gt;        if arity == None:&lt;br /&gt;            raise ParseError&lt;br /&gt;        args = []&lt;br /&gt;        index = index + 1&lt;br /&gt;        while len(args) &amp;lt; arity:&lt;br /&gt;            if index &amp;gt;= len(tokens):&lt;br /&gt;                raise ParseError&lt;br /&gt;            arg, index = self._parse_expr(tokens, index, patterns, fns)&lt;br /&gt;            args.append(arg)&lt;br /&gt;        return CallExpr(token, args), index&lt;br /&gt;&lt;br /&gt;    def _parse_literal(self, tokens, index):&lt;br /&gt;        bits = []&lt;br /&gt;        while True:&lt;br /&gt;            if index &amp;gt;= len(tokens):&lt;br /&gt;                return LiteralExpr(bits), index&lt;br /&gt;            elif tokens[index] == '0':&lt;br /&gt;                bits.append(False)&lt;br /&gt;            elif tokens[index] == '1':&lt;br /&gt;                bits.append(True)&lt;br /&gt;            elif tokens[index] == '_':&lt;br /&gt;                return LiteralExpr(bits), index + 1&lt;br /&gt;            else:&lt;br /&gt;                return LiteralExpr(bits), index&lt;br /&gt;            index = index + 1&lt;br /&gt;&lt;br /&gt;def collect_defns(fns, tokens):&lt;br /&gt;    def defns_list():&lt;br /&gt;        while True:&lt;br /&gt;            yield Defn(tokens)&lt;br /&gt;    for defn in defns_list():&lt;br /&gt;        if defn.name in fns:&lt;br /&gt;            if len(fns[defn.name][0].patterns) != len(defn.patterns):&lt;br /&gt;                raise ParseError&lt;br /&gt;            fns[defn.name].append(defn)&lt;br /&gt;        else:&lt;br /&gt;            fns[defn.name] = [defn]&lt;br /&gt;&lt;br /&gt;def parse_file(fns, file):&lt;br /&gt;    def chars():&lt;br /&gt;        for line in file:&lt;br /&gt;            for char in line:&lt;br /&gt;                yield char&lt;br /&gt;    collect_defns(fns, tokens(chars()))&lt;br /&gt;&lt;br /&gt;def parse_bodies(fns):&lt;br /&gt;    for name, defns in fns.items():&lt;br /&gt;        for defn in defns:&lt;br /&gt;            defn.parse_body(fns)&lt;br /&gt;&lt;br /&gt;class UndefinedFunctionError(BaseException):&lt;br /&gt;    pass&lt;br /&gt;&lt;br /&gt;class NilVal:&lt;br /&gt;    def value():&lt;br /&gt;        return None&lt;br /&gt;&lt;br /&gt;    def next():&lt;br /&gt;        assert False&lt;br /&gt;&lt;br /&gt;class LiteralVal:&lt;br /&gt;    def __init__(self, bits, index):&lt;br /&gt;        self._bits = bits&lt;br /&gt;        self._index = index&lt;br /&gt;        self._next = None&lt;br /&gt;&lt;br /&gt;    def value(self):&lt;br /&gt;        if self._index &amp;gt;= len(self._bits):&lt;br /&gt;            return None&lt;br /&gt;        else:&lt;br /&gt;            return self._bits[self._index]&lt;br /&gt;&lt;br /&gt;    def next(self):&lt;br /&gt;        if self._next == None:&lt;br /&gt;            assert self._index &amp;lt; len(self._bits)&lt;br /&gt;            self._next = LiteralVal(self._bits, self._index + 1)&lt;br /&gt;        return self._next&lt;br /&gt;&lt;br /&gt;class FileVal:&lt;br /&gt;    def __init__(self, file, index = 7, byte = 0):&lt;br /&gt;        self._file = file&lt;br /&gt;        self._index = index&lt;br /&gt;        self._byte = byte&lt;br /&gt;        self._next = None&lt;br /&gt;&lt;br /&gt;    def value(self):&lt;br /&gt;        if self._byte == None:&lt;br /&gt;            assert self._index == 7&lt;br /&gt;            bytes = self._file.read(1)&lt;br /&gt;            if len(bytes) == 0:&lt;br /&gt;                self._byte = -1&lt;br /&gt;                self._file.close()&lt;br /&gt;            else:&lt;br /&gt;                self._byte = bytes[0]&lt;br /&gt;        if self._byte &amp;lt; 0:&lt;br /&gt;            return None&lt;br /&gt;        return (self._byte &amp;amp; (1 &amp;lt;&amp;lt; self._index)) != 0&lt;br /&gt;&lt;br /&gt;    def next(self):&lt;br /&gt;        if self._next == None:&lt;br /&gt;            self.value()&lt;br /&gt;            assert self.value() != None&lt;br /&gt;            if self._index &amp;gt; 0:&lt;br /&gt;                self._next = FileVal(self._file, self._index - 1, self._byte)&lt;br /&gt;            else:&lt;br /&gt;                self._next = FileVal(self._file, 7, None)&lt;br /&gt;        return self._next&lt;br /&gt;&lt;br /&gt;class ConcatVal:&lt;br /&gt;    def __init__(self, head, tail):&lt;br /&gt;        self._head = head&lt;br /&gt;        self._tail = tail&lt;br /&gt;        self._value = None&lt;br /&gt;        self._next = None&lt;br /&gt;&lt;br /&gt;    def value(self):&lt;br /&gt;        if self._head != None:&lt;br /&gt;            bit = self._head.value()&lt;br /&gt;            if bit != None:&lt;br /&gt;                self._value = bit&lt;br /&gt;                self._next = ConcatVal(self._head.next(), self._tail)&lt;br /&gt;            else:&lt;br /&gt;                self._value = self._tail.value()&lt;br /&gt;                if self._value != None:&lt;br /&gt;                    self._next = self._tail.next()&lt;br /&gt;            self._head = None&lt;br /&gt;            self._tail = None&lt;br /&gt;        return self._value&lt;br /&gt;&lt;br /&gt;    def next(self):&lt;br /&gt;        if self._head != None:&lt;br /&gt;            self.value()&lt;br /&gt;            assert self._value != None&lt;br /&gt;        return self._next&lt;br /&gt;&lt;br /&gt;class ExprVal:&lt;br /&gt;    def __init__(self, fns, expr, bindings):&lt;br /&gt;        self._fns = fns&lt;br /&gt;        self._expr = expr&lt;br /&gt;        self._bindings = bindings&lt;br /&gt;        self._value = None&lt;br /&gt;        self._next = None&lt;br /&gt;&lt;br /&gt;    def value(self):&lt;br /&gt;        if self._expr != None:&lt;br /&gt;            if self._expr.__class__ is LiteralExpr:&lt;br /&gt;                self._value, self._next = self._eval_literal()&lt;br /&gt;            elif self._expr.__class__ is BoundExpr:&lt;br /&gt;                self._value, self._next = self._eval_bound()&lt;br /&gt;            elif self._expr.__class__ is ConcatExpr:&lt;br /&gt;                self._value, self._next = self._eval_concat()&lt;br /&gt;            elif self._expr.__class__ is CallExpr:&lt;br /&gt;                self._value, self._next = self._eval_call()&lt;br /&gt;            else:&lt;br /&gt;                assert False&lt;br /&gt;            self._expr = None&lt;br /&gt;        return self._value&lt;br /&gt;&lt;br /&gt;    def next(self):&lt;br /&gt;        if self._expr != None:&lt;br /&gt;            self.value()&lt;br /&gt;            assert self._value != None&lt;br /&gt;        return self._next&lt;br /&gt;&lt;br /&gt;    def _eval_literal(self):&lt;br /&gt;        if self._expr.bits == []:&lt;br /&gt;            return None, None&lt;br /&gt;        else:&lt;br /&gt;            return self._expr.bits[0], LiteralVal(self._expr.bits, 1)&lt;br /&gt;&lt;br /&gt;    def _eval_bound(self):&lt;br /&gt;        val = self._bindings[self._expr.index]&lt;br /&gt;        bit = val.value()&lt;br /&gt;        return bit, val.next() if bit != None else None&lt;br /&gt;&lt;br /&gt;    def _eval_concat(self):&lt;br /&gt;        head = ExprVal(self._fns, self._expr.head, self._bindings)&lt;br /&gt;        tail = ExprVal(self._fns, self._expr.tail, self._bindings)&lt;br /&gt;        bit = head.value()&lt;br /&gt;        if bit != None:&lt;br /&gt;            return bit, ConcatVal(head.next(), tail)&lt;br /&gt;        else:&lt;br /&gt;            bit = tail.value()&lt;br /&gt;            return bit, tail.next() if bit != None else None&lt;br /&gt;&lt;br /&gt;    def _eval_call(self):&lt;br /&gt;        val = apply(self._fns, self._expr.fn,&lt;br /&gt;                    [ExprVal(self._fns, arg, self._bindings)&lt;br /&gt;                     for arg in self._expr.args])&lt;br /&gt;        bit = val.value()&lt;br /&gt;        return bit, val.next() if bit != None else None&lt;br /&gt;&lt;br /&gt;def apply(fns, fn, args):&lt;br /&gt;    def match(pattern, val):&lt;br /&gt;        for bit in pattern.match:&lt;br /&gt;            b = val.value()&lt;br /&gt;            if b == None or b != bit:&lt;br /&gt;                return False&lt;br /&gt;            val = val.next()&lt;br /&gt;        if pattern.is_literal():&lt;br /&gt;            return val.value() == None&lt;br /&gt;        elif pattern.is_wild():&lt;br /&gt;            return True&lt;br /&gt;        else:&lt;br /&gt;            return val&lt;br /&gt;&lt;br /&gt;    for defn in fns[fn]:&lt;br /&gt;        bindings = []&lt;br /&gt;        for pattern, arg in zip(defn.patterns, args):&lt;br /&gt;            binding = match(pattern, arg)&lt;br /&gt;            if binding == False:&lt;br /&gt;                break&lt;br /&gt;            elif binding == True:&lt;br /&gt;                continue&lt;br /&gt;            else:&lt;br /&gt;                bindings.append(binding)&lt;br /&gt;        else:&lt;br /&gt;            return ExprVal(fns, defn.expr, bindings)&lt;br /&gt;    raise UndefinedFunctionError&lt;br /&gt;&lt;br /&gt;def write_value(value, stream):&lt;br /&gt;    b = 0&lt;br /&gt;    bit = 128&lt;br /&gt;    while value.value() != None:&lt;br /&gt;        if value.value():&lt;br /&gt;            b = b | bit&lt;br /&gt;        if bit == 1:&lt;br /&gt;            stream.write(bytes([b]))&lt;br /&gt;            bit = 128&lt;br /&gt;            b = 0&lt;br /&gt;        else:&lt;br /&gt;            bit = bit &amp;gt;&amp;gt; 1&lt;br /&gt;        value = value.next()&lt;br /&gt;        &lt;br /&gt;def parse_sources(files):&lt;br /&gt;    fns = {}&lt;br /&gt;    for file in files:&lt;br /&gt;        with open(file) as f:&lt;br /&gt;            parse_file(fns, f)&lt;br /&gt;    parse_bodies(fns)&lt;br /&gt;    return fns&lt;br /&gt;&lt;br /&gt;def interpreter():&lt;br /&gt;    source_files = []&lt;br /&gt;    fn = None&lt;br /&gt;    args = None&lt;br /&gt;    stdin = FileVal(sys.stdin.buffer)&lt;br /&gt;    for arg in sys.argv[1:]:&lt;br /&gt;        if fn == None:&lt;br /&gt;            if arg != '-':&lt;br /&gt;                source_files.append(arg)&lt;br /&gt;            else:&lt;br /&gt;                fn = os.path.basename(source_files[0])&lt;br /&gt;                if fn.find('.') &amp;gt; 0:&lt;br /&gt;                    fn = fn[0:fn.find('.')]&lt;br /&gt;        elif args == None:&lt;br /&gt;            args = []&lt;br /&gt;            fn = arg&lt;br /&gt;        elif arg == '-':&lt;br /&gt;            args.append(stdin)&lt;br /&gt;        else:&lt;br /&gt;            args.append(FileVal(open(arg, "rb")))&lt;br /&gt;    if fn == None:&lt;br /&gt;        fn = os.path.basename(source_files[-1])&lt;br /&gt;        if fn.find('.') &amp;gt; 0:&lt;br /&gt;            fn = fn[0:fn.find('.')]&lt;br /&gt;    if args == None:&lt;br /&gt;        args = []&lt;br /&gt;    fns = parse_sources(source_files)&lt;br /&gt;    arity = len(fns[fn][0].patterns)&lt;br /&gt;    if len(args) &amp;lt; arity:&lt;br /&gt;        args.append(stdin)&lt;br /&gt;    while len(args) &amp;lt; arity:&lt;br /&gt;        args.append(NilVal())&lt;br /&gt;    write_value(apply(fns, fn, args[0:arity]), sys.stdout.buffer)&lt;br /&gt;&lt;br /&gt;interpreter()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-3013241451424395054?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/3013241451424395054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/04/i-had-never-taken-serious-look-at.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3013241451424395054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3013241451424395054'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/04/i-had-never-taken-serious-look-at.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-7814581347091131200</id><published>2010-04-05T00:00:00.000-07:00</published><updated>2010-04-05T00:00:05.843-07:00</updated><title type='text'></title><content type='html'>Here is a &lt;a href="/2009/12/resol-programming-language.html"&gt;RESOL&lt;/a&gt; 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.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import java.io.FileReader;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;import java.io.InputStream;&lt;br /&gt;import java.io.OutputStream;&lt;br /&gt;import java.io.Reader;&lt;br /&gt;import java.util.Arrays;&lt;br /&gt;import java.util.HashMap;&lt;br /&gt;import java.util.Iterator;&lt;br /&gt;import java.util.LinkedList;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;public class ri {&lt;br /&gt;    public static class RESOLException extends RuntimeException {&lt;br /&gt;        public RESOLException(Statement statement, String message) {&lt;br /&gt;            super(statement.getLocation() + ": " + message);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public RESOLException(Statement statement, String message, Throwable t) {&lt;br /&gt;            super(statement.getLocation() + ": " + message, t);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public RESOLException(String fileName, int lineNumber, String message) {&lt;br /&gt;            super(fileName + ":" + lineNumber + ": " + message);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public RESOLException(String fileName, int lineNumber, String message, Throwable t) {&lt;br /&gt;            super(fileName + ":" + lineNumber + ": " + message, t);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class BitInputStream {&lt;br /&gt;        private InputStream in;&lt;br /&gt;        private int currentByte;&lt;br /&gt;        private int currentBit = 0;&lt;br /&gt;        private boolean eof = false;&lt;br /&gt;&lt;br /&gt;        public BitInputStream(InputStream in) {&lt;br /&gt;            this.in = in;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean eof() {&lt;br /&gt;            return eof;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean read() throws IOException {&lt;br /&gt;            if (currentBit == 0) {&lt;br /&gt;                currentByte = in.read();&lt;br /&gt;                if (currentByte &amp;lt; 0) {&lt;br /&gt;                    eof = true;&lt;br /&gt;                    in.close();&lt;br /&gt;                    return false;&lt;br /&gt;                }&lt;br /&gt;                currentBit = 128;&lt;br /&gt;            }&lt;br /&gt;            try {&lt;br /&gt;                return (currentByte &amp;amp; currentBit) != 0;&lt;br /&gt;            } finally {&lt;br /&gt;                currentBit &amp;gt;&amp;gt;&amp;gt;= 1;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class BitOutputStream {&lt;br /&gt;        private OutputStream out;&lt;br /&gt;        private int currentByte = 0;&lt;br /&gt;        private int currentBit = 128;&lt;br /&gt;&lt;br /&gt;        public BitOutputStream(OutputStream out) {&lt;br /&gt;            this.out = out;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void write(boolean b) throws IOException {&lt;br /&gt;            if (b)&lt;br /&gt;                currentByte |= currentBit;&lt;br /&gt;            currentBit &amp;gt;&amp;gt;&amp;gt;= 1;&lt;br /&gt;            if (currentBit == 0) {&lt;br /&gt;                out.write(currentByte);&lt;br /&gt;                currentByte = 0;&lt;br /&gt;                currentBit = 128;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class Statement {&lt;br /&gt;        public enum Op { DATA, CALL, CONTINUE, IF, STOP }&lt;br /&gt;&lt;br /&gt;        private String fileName;&lt;br /&gt;        private int lineNumber;&lt;br /&gt;        private String label;&lt;br /&gt;        private Op op;&lt;br /&gt;        private String arg1;&lt;br /&gt;        private String arg2;&lt;br /&gt;        private Statement next = null;&lt;br /&gt;        private int itemSize = 0;&lt;br /&gt;        private LinkedList&amp;lt;LinkedList&amp;lt;Integer&amp;gt;&amp;gt; queueStack = null;&lt;br /&gt;        private LinkedList&amp;lt;Statement&amp;gt; callStack = null;&lt;br /&gt;&lt;br /&gt;        public Statement(String fileName, int lineNumber, String label, Op op, String arg1, String arg2) {&lt;br /&gt;            this.fileName = fileName;&lt;br /&gt;            this.lineNumber = lineNumber;&lt;br /&gt;            this.label = label == null || label.length() == 0 ? null : label;&lt;br /&gt;            this.op = op;&lt;br /&gt;            this.arg1 = arg1;&lt;br /&gt;            this.arg2 = arg2;&lt;br /&gt;            switch (op) {&lt;br /&gt;            case DATA:&lt;br /&gt;                if (arg1 == null)&lt;br /&gt;                    throw new RESOLException(this, "DATA STATEMENT REQUIRES AN ARGUMENT");&lt;br /&gt;                if (label != null) {&lt;br /&gt;                    itemSize = Integer.parseInt(arg1, 10);&lt;br /&gt;                    queueStack = new LinkedList&amp;lt;LinkedList&amp;lt;Integer&amp;gt;&amp;gt;();&lt;br /&gt;                    queueStack.addFirst(new LinkedList&amp;lt;Integer&amp;gt;());&lt;br /&gt;                    if (arg2 != null)&lt;br /&gt;                        enqueueLiteral(arg2);&lt;br /&gt;                }&lt;br /&gt;                break;&lt;br /&gt;            case CALL:&lt;br /&gt;                if (arg1 == null)&lt;br /&gt;                    throw new RESOLException(this, "CALL STATEMENT REQUIRES AN ARGUMENT");&lt;br /&gt;                break;&lt;br /&gt;            case CONTINUE:&lt;br /&gt;                if (arg1 == null)&lt;br /&gt;                    throw new RESOLException(this, "CONTINUE STATEMENT REQUIRES AN ARGUMENT");&lt;br /&gt;                break;&lt;br /&gt;            case IF:&lt;br /&gt;                if (arg1 == null || arg2 == null)&lt;br /&gt;                    throw new RESOLException(this, "IF STATEMENT REQUIRES TWO ARGUMENTS");&lt;br /&gt;                break;&lt;br /&gt;            case STOP:&lt;br /&gt;                if (arg1 != null || arg2 != null)&lt;br /&gt;                    throw new RESOLException(this, "STOP STATEMENT CANNOT HAVE ANY ARGUMENTS");&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;            if (label != null)&lt;br /&gt;                callStack = new LinkedList&amp;lt;Statement&amp;gt;();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected String getFileName() {&lt;br /&gt;            return fileName;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected int getLineNumber() {&lt;br /&gt;            return lineNumber;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public String getLabel() {&lt;br /&gt;            return label;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected Op getOp() {&lt;br /&gt;            return op;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected String getArg1() {&lt;br /&gt;            return arg1;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected String getArg2() {&lt;br /&gt;            return arg2;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void setNext(Statement next) {&lt;br /&gt;            this.next = next;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public String getLocation() {&lt;br /&gt;            return fileName + ":" + lineNumber;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void enqueueLiteral(String literal) {&lt;br /&gt;            for (int i = 0; i &amp;lt; literal.length(); i++)&lt;br /&gt;                enqueueDigit(literal.charAt(i) - '0');&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void enqueueItem(LinkedList&amp;lt;Integer&amp;gt; queue, int queueItemSize) {&lt;br /&gt;            for (int i = 0; i &amp;lt; Math.min(queue.size(), queueItemSize); i++)&lt;br /&gt;                enqueueDigit(queue.get(i));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void enqueueDigit(int digit) {&lt;br /&gt;            assert digit &amp;gt;= 0 &amp;amp;&amp;amp; digit &amp;lt;= 9;&lt;br /&gt;            queueStack.getFirst().addLast(digit);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void dequeueItem() {&lt;br /&gt;            for (int i = 0; i &amp;lt; itemSize &amp;amp;&amp;amp; queueStack.getFirst().size() &amp;gt; 0; i++)&lt;br /&gt;                queueStack.getFirst().removeFirst();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public int getCurrentItemSize() {&lt;br /&gt;            return Math.min(itemSize, queueStack.getFirst().size());&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public int getItemDigit(int index) {&lt;br /&gt;            assert index &amp;lt; itemSize;&lt;br /&gt;            return queueStack.getFirst().get(index);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Statement popCall(Statement t, Statement n) {&lt;br /&gt;            if (queueStack != null)&lt;br /&gt;                queueStack.removeFirst();&lt;br /&gt;            return callStack.removeFirst();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void pushCall(Statement t, Statement n) {&lt;br /&gt;            if (queueStack != null)&lt;br /&gt;                queueStack.addFirst(new LinkedList&amp;lt;Integer&amp;gt;());&lt;br /&gt;            callStack.addFirst(n);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean isData() {&lt;br /&gt;            return op == Op.DATA;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static void enqueueTo(Statement statement, String arg, Map&amp;lt;String,Statement&amp;gt; labels) {&lt;br /&gt;            if (!statement.isData())&lt;br /&gt;                return;&lt;br /&gt;            Statement argStatement = labels.get(arg);&lt;br /&gt;            if (argStatement == null)&lt;br /&gt;                statement.enqueueLiteral(arg);&lt;br /&gt;            else&lt;br /&gt;                for (int i = 0; i &amp;lt; argStatement.getCurrentItemSize(); i++)&lt;br /&gt;                    statement.enqueueDigit(argStatement.getItemDigit(i));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static boolean equalTo(String arg1, String arg2, Map&amp;lt;String,Statement&amp;gt; labels) {&lt;br /&gt;            if (arg1.equals(arg2))&lt;br /&gt;                return true;&lt;br /&gt;            Statement statement1 = labels.get(arg1);&lt;br /&gt;            Statement statement2 = labels.get(arg2);&lt;br /&gt;            if (statement1 == null &amp;amp;&amp;amp; statement2 == null)&lt;br /&gt;                return false;&lt;br /&gt;            if (statement1 != null &amp;amp;&amp;amp; statement2 != null) {&lt;br /&gt;                if (statement1.getCurrentItemSize() != statement2.getCurrentItemSize())&lt;br /&gt;                    return false;&lt;br /&gt;                for (int i = 0; i &amp;lt; statement1.getCurrentItemSize(); i++)&lt;br /&gt;                    if (statement1.getItemDigit(i) != statement2.getItemDigit(i))&lt;br /&gt;                        return false;&lt;br /&gt;                return true;&lt;br /&gt;            }&lt;br /&gt;            if (statement1 == null) {&lt;br /&gt;                statement1 = statement2;&lt;br /&gt;                arg2 = arg1;&lt;br /&gt;            }&lt;br /&gt;            if (statement1.getCurrentItemSize() != arg2.length())&lt;br /&gt;                return false;&lt;br /&gt;            for (int i = 0; i &amp;lt; arg2.length(); i++)&lt;br /&gt;                if (statement1.getItemDigit(i) != arg2.charAt(i) - '0')&lt;br /&gt;                    return false;&lt;br /&gt;            return true;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Statement run(Map&amp;lt;String,Statement&amp;gt; labels) {&lt;br /&gt;            Statement statement = null;&lt;br /&gt;            Statement statement2 = null;&lt;br /&gt;            switch (op) {&lt;br /&gt;            case DATA:&lt;br /&gt;                statement = labels.get(arg1);&lt;br /&gt;                if (statement == null || !statement.isData())&lt;br /&gt;                    break;&lt;br /&gt;                if (arg2 == null)&lt;br /&gt;                    statement.dequeueItem();&lt;br /&gt;                else&lt;br /&gt;                    enqueueTo(statement, arg2, labels);&lt;br /&gt;                break;&lt;br /&gt;&lt;br /&gt;            case CALL:&lt;br /&gt;                statement = labels.get(arg1);&lt;br /&gt;                if (statement == null)&lt;br /&gt;                    throw new RESOLException(this, "CALL TO UNKNOWN LABEL: " + arg1);&lt;br /&gt;                if (next == null)&lt;br /&gt;                    throw new RESOLException(this, "UNEXPECTED END OF PROGRAM");&lt;br /&gt;                statement.pushCall(this, next);&lt;br /&gt;                if (arg2 != null)&lt;br /&gt;                    enqueueTo(statement, arg2, labels);&lt;br /&gt;                return statement;&lt;br /&gt;&lt;br /&gt;            case CONTINUE:&lt;br /&gt;                statement = labels.get(arg1);&lt;br /&gt;                if (statement == null)&lt;br /&gt;                    throw new RESOLException(this, "CONTINUE FROM UNKNOWN LABEL: " + arg1);&lt;br /&gt;                if (!statement.isData() || statement.getCurrentItemSize() == 0)&lt;br /&gt;                    return statement.popCall(this, next);&lt;br /&gt;                if (arg2 == null)&lt;br /&gt;                    return statement;&lt;br /&gt;                statement = labels.get(arg2);&lt;br /&gt;                if (statement == null)&lt;br /&gt;                    throw new RESOLException(this, "CONTINUE FROM UNKNOWN LABEL: " + arg2);&lt;br /&gt;                return statement;&lt;br /&gt;&lt;br /&gt;            case IF:&lt;br /&gt;                if (!equalTo(arg1, arg2, labels)) {&lt;br /&gt;                    if (next == null || next.next == null)&lt;br /&gt;                        throw new RESOLException(this, "UNEXPECTED END OF PROGRAM");&lt;br /&gt;                    return next.next;&lt;br /&gt;                }&lt;br /&gt;                break;&lt;br /&gt;&lt;br /&gt;            case STOP:&lt;br /&gt;                return null;&lt;br /&gt;            }&lt;br /&gt;            if (next == null)&lt;br /&gt;                throw new RESOLException(this, "UNEXPECTED END OF PROGRAM");&lt;br /&gt;            return next;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class FirstStatement extends Statement {&lt;br /&gt;        private boolean encodeOutput;&lt;br /&gt;        private boolean isIO;&lt;br /&gt;        private int[] inputItem = null;&lt;br /&gt;        private int inputItemSize;&lt;br /&gt;        private BitInputStream in;&lt;br /&gt;        private int[] outputItem = null;&lt;br /&gt;        private int outputItemSize;&lt;br /&gt;        private BitOutputStream out;&lt;br /&gt;        private int itemBitCount;&lt;br /&gt;&lt;br /&gt;        public FirstStatement(Statement statement, boolean encodeOutput) {&lt;br /&gt;            super(statement.getFileName(), statement.getLineNumber(), statement.getLabel(), statement.getOp(), statement.getArg1(), statement.getArg2());&lt;br /&gt;            this.encodeOutput = encodeOutput;&lt;br /&gt;            isIO = getLabel() != null &amp;amp;&amp;amp; getOp() == Op.DATA;&lt;br /&gt;            if (isIO) {&lt;br /&gt;                int itemSize = Integer.parseInt(getArg1(), 10);&lt;br /&gt;                inputItem = new int[itemSize];&lt;br /&gt;                inputItemSize = 0;&lt;br /&gt;                in = new BitInputStream(System.in);&lt;br /&gt;                outputItem = new int[itemSize];&lt;br /&gt;                outputItemSize = 0;&lt;br /&gt;                out = new BitOutputStream(System.out);&lt;br /&gt;&lt;br /&gt;                int test = 0;&lt;br /&gt;                for (int i = 0; i &amp;lt; itemSize; i++)&lt;br /&gt;                    test = test*10 + 9;&lt;br /&gt;                itemBitCount = 0;&lt;br /&gt;                boolean decCount = false;&lt;br /&gt;                while (test &amp;gt; 0) {&lt;br /&gt;                    if ((test &amp;amp; 1) == 0)&lt;br /&gt;                        decCount = true;&lt;br /&gt;                    test &amp;gt;&amp;gt;&amp;gt;= 1;&lt;br /&gt;                    itemBitCount++;&lt;br /&gt;                }&lt;br /&gt;                if (decCount)&lt;br /&gt;                    itemBitCount--;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void enqueueDigit(int digit) {&lt;br /&gt;            if (!encodeOutput) {&lt;br /&gt;                System.out.print(digit);&lt;br /&gt;                return;&lt;br /&gt;            }&lt;br /&gt;            outputItem[outputItemSize++] = digit;&lt;br /&gt;            if (outputItemSize &amp;gt;= outputItem.length)&lt;br /&gt;                flushOutput();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void flushOutput() {&lt;br /&gt;            int item = 0;&lt;br /&gt;            for (int i = 0; i &amp;lt; outputItem.length; i++)&lt;br /&gt;                item = item*10 + outputItem[i];&lt;br /&gt;            int bit = 1 &amp;lt;&amp;lt; (itemBitCount - 1);&lt;br /&gt;            while (bit != 0) {&lt;br /&gt;                try {&lt;br /&gt;                    out.write((item &amp;amp; bit) != 0);&lt;br /&gt;                } catch (IOException e) {&lt;br /&gt;                    throw new RESOLException(this, "IO EXCEPTION", e);&lt;br /&gt;                }&lt;br /&gt;                bit &amp;gt;&amp;gt;&amp;gt;= 1;&lt;br /&gt;            }&lt;br /&gt;            outputItemSize = 0;&lt;br /&gt;            Arrays.fill(outputItem, 0);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void dequeueItem() {&lt;br /&gt;            readItem();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public int getCurrentItemSize() {&lt;br /&gt;            if (inputItemSize == 0)&lt;br /&gt;                readItem();&lt;br /&gt;            return inputItemSize;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public int getItemDigit(int index) {&lt;br /&gt;            return inputItem[index];&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void readItem() {&lt;br /&gt;            inputItemSize = 0;&lt;br /&gt;            if (in.eof())&lt;br /&gt;                return;&lt;br /&gt;            int item = 0;&lt;br /&gt;            int bit = 1 &amp;lt;&amp;lt; (itemBitCount - 1);&lt;br /&gt;            while (!in.eof() &amp;amp;&amp;amp; bit != 0) {&lt;br /&gt;                boolean b;&lt;br /&gt;                try {&lt;br /&gt;                    b = in.read();&lt;br /&gt;                } catch (IOException e) {&lt;br /&gt;                    throw new RESOLException(this, "IO EXCEPTION", e);&lt;br /&gt;                }&lt;br /&gt;                if (in.eof())&lt;br /&gt;                    break;&lt;br /&gt;                if (b)&lt;br /&gt;                    item |= bit;&lt;br /&gt;                bit &amp;gt;&amp;gt;&amp;gt;= 1;&lt;br /&gt;            }&lt;br /&gt;            for (int i = inputItem.length - 1; i &amp;gt;= 0; i--) {&lt;br /&gt;                inputItem[i] = item%10;&lt;br /&gt;                item = item/10;&lt;br /&gt;            }&lt;br /&gt;            inputItemSize = inputItem.length;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Statement popCall(Statement t, Statement n) {&lt;br /&gt;            if (!isIO)&lt;br /&gt;                return super.popCall(t, n);&lt;br /&gt;            if (n == null)&lt;br /&gt;                throw new RESOLException(t, "UNEXPECTED END OF PROGRAM");&lt;br /&gt;            return n;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void pushCall(Statement t, Statement n) {&lt;br /&gt;            if (isIO)&lt;br /&gt;                throw new RESOLException(t, "ILLEGAL CALL");&lt;br /&gt;            super.pushCall(t, n);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class Parser implements Iterable&amp;lt;Statement&amp;gt;, Iterator&amp;lt;Statement&amp;gt; {&lt;br /&gt;        private Reader in;&lt;br /&gt;        private String fileName;&lt;br /&gt;        private int lineNumber;&lt;br /&gt;        private int statementLineNumber = 1;&lt;br /&gt;        private StringBuilder currentLabel = new StringBuilder();&lt;br /&gt;        private StringBuilder currentStatement = new StringBuilder();&lt;br /&gt;        private Statement statement = null;&lt;br /&gt;        private boolean eof = false;&lt;br /&gt;&lt;br /&gt;        public Parser(String fileName) throws IOException {&lt;br /&gt;            this(fileName, new FileReader(fileName));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Parser(String fileName, Reader in) {&lt;br /&gt;            this.fileName = fileName;&lt;br /&gt;            this.in = in;&lt;br /&gt;            this.lineNumber = 0;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Iterator&amp;lt;Statement&amp;gt; iterator() {&lt;br /&gt;            return this;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public boolean hasNext() {&lt;br /&gt;            while (statement == null &amp;amp;&amp;amp; !eof)&lt;br /&gt;                try {&lt;br /&gt;                    readLine();&lt;br /&gt;                } catch (IOException e) {&lt;br /&gt;                    throw new RESOLException(fileName, lineNumber, "IO EXCEPTION", e);&lt;br /&gt;                }&lt;br /&gt;            return statement != null;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Statement next() {&lt;br /&gt;            hasNext();&lt;br /&gt;            try {&lt;br /&gt;                return statement;&lt;br /&gt;            } finally {&lt;br /&gt;                statement = null;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void remove() {&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void readLine() throws IOException {&lt;br /&gt;            lineNumber++;&lt;br /&gt;            int column = 1;&lt;br /&gt;            int c = in.read();&lt;br /&gt;            if (c &amp;lt; 0) {&lt;br /&gt;                eof = true;&lt;br /&gt;                in.close();&lt;br /&gt;                finishStatement();&lt;br /&gt;                return;&lt;br /&gt;            }&lt;br /&gt;            if (c == 'C') {&lt;br /&gt;                finishStatement();&lt;br /&gt;                statementLineNumber++;&lt;br /&gt;                while (c &amp;gt;= 0 &amp;amp;&amp;amp; c != '\n')&lt;br /&gt;                    c = in.read();&lt;br /&gt;                if (c &amp;lt; 0) {&lt;br /&gt;                    eof = true;&lt;br /&gt;                    in.close();&lt;br /&gt;                }&lt;br /&gt;                return;&lt;br /&gt;            }&lt;br /&gt;            StringBuilder sb = new StringBuilder();&lt;br /&gt;            while (column &amp;lt; 6) {&lt;br /&gt;                if (c != ' ') {&lt;br /&gt;                    if (isDigit(c))&lt;br /&gt;                        sb.append((char) c);&lt;br /&gt;                    else&lt;br /&gt;                        throw new RESOLException(fileName, lineNumber, "ILLEGAL LABEL");&lt;br /&gt;                }&lt;br /&gt;                c = in.read();&lt;br /&gt;                column++;&lt;br /&gt;                if (c &amp;lt; 0) {&lt;br /&gt;                    eof = true;&lt;br /&gt;                    in.close();&lt;br /&gt;                    if (sb.length() &amp;gt; 0)&lt;br /&gt;                        throw new RESOLException(fileName, lineNumber, "UNEXPECTED EOF");&lt;br /&gt;                    finishStatement();&lt;br /&gt;                    return;&lt;br /&gt;                }&lt;br /&gt;                if (c == '\n') {&lt;br /&gt;                    finishStatement();&lt;br /&gt;                    return;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            if (c == ' ')&lt;br /&gt;                finishStatement();&lt;br /&gt;            currentLabel.append(sb);&lt;br /&gt;            for (;;) {&lt;br /&gt;                c = in.read();&lt;br /&gt;                column++;&lt;br /&gt;                if (c &amp;lt; 0) {&lt;br /&gt;                    eof = true;&lt;br /&gt;                    in.close();&lt;br /&gt;                    finishStatement();&lt;br /&gt;                    return;&lt;br /&gt;                }&lt;br /&gt;                if (c == '\n')&lt;br /&gt;                    return;&lt;br /&gt;                if (c == ' ' || column &amp;gt; 72)&lt;br /&gt;                    continue;&lt;br /&gt;                if (isDigit(c) || isLetter(c) || c == ',')&lt;br /&gt;                    currentStatement.append((char) c);&lt;br /&gt;                else&lt;br /&gt;                    throw new RESOLException(fileName, lineNumber, "UNEXPECTED CHARACTER");&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private boolean isDigit(int c) {&lt;br /&gt;            return c &amp;gt;= '0' &amp;amp;&amp;amp; c &amp;lt;= '9';&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private boolean isLetter(int c) {&lt;br /&gt;            return c &amp;gt;= 'A' &amp;amp;&amp;amp; c &amp;lt;= 'Z';&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void finishStatement() {&lt;br /&gt;            assert statement == null;&lt;br /&gt;            if (currentStatement.length() == 0 &amp;amp;&amp;amp; currentLabel.length() == 0) {&lt;br /&gt;                statementLineNumber = lineNumber;&lt;br /&gt;                return;&lt;br /&gt;            }&lt;br /&gt;            int i = 0;&lt;br /&gt;            while (i &amp;lt; currentStatement.length() &amp;amp;&amp;amp; isLetter(currentStatement.charAt(i)))&lt;br /&gt;                i++;&lt;br /&gt;            Statement.Op op;&lt;br /&gt;            try {&lt;br /&gt;                op = Enum.valueOf(Statement.Op.class, currentStatement.substring(0, i));&lt;br /&gt;            } catch (IllegalArgumentException e) {&lt;br /&gt;                throw new RESOLException(fileName, statementLineNumber, "UNRECOGNIZED STATEMENT");&lt;br /&gt;            }&lt;br /&gt;            String arg1 = null;&lt;br /&gt;            int i2 = i;&lt;br /&gt;            while (i2 &amp;lt; currentStatement.length() &amp;amp;&amp;amp; isDigit(currentStatement.charAt(i2)))&lt;br /&gt;                i2++;&lt;br /&gt;            if (i2 &amp;lt; currentStatement.length()) {&lt;br /&gt;                if (i2 == i || currentStatement.charAt(i2) != ',')&lt;br /&gt;                    throw new RESOLException(fileName, statementLineNumber, "ILLEGAL ARGUMENT");&lt;br /&gt;            }&lt;br /&gt;            if (i &amp;lt; i2)&lt;br /&gt;                arg1 = currentStatement.substring(i, i2);&lt;br /&gt;            String arg2 = null;&lt;br /&gt;            i = i2 + 1;&lt;br /&gt;            i2 = i;&lt;br /&gt;            while (i2 &amp;lt; currentStatement.length() &amp;amp;&amp;amp; isDigit(currentStatement.charAt(i2)))&lt;br /&gt;                i2++;&lt;br /&gt;            if (i2 &amp;lt; currentStatement.length())&lt;br /&gt;                throw new RESOLException(fileName, statementLineNumber, "ILLEGAL ARGUMENT");&lt;br /&gt;            if (i &amp;lt; i2)&lt;br /&gt;                arg2 = currentStatement.substring(i, i2);&lt;br /&gt;            statement = new Statement(fileName, statementLineNumber, currentLabel.toString(), op, arg1, arg2);&lt;br /&gt;            statementLineNumber = lineNumber;&lt;br /&gt;            currentLabel.setLength(0);&lt;br /&gt;            currentStatement.setLength(0);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        boolean encodeOutput = true;&lt;br /&gt;        int index = 0;&lt;br /&gt;        if (index &amp;lt; args.length &amp;amp;&amp;amp; "-r".equals(args[index])) {&lt;br /&gt;            encodeOutput = false;&lt;br /&gt;            index++;&lt;br /&gt;        }&lt;br /&gt;        FirstStatement first = null;&lt;br /&gt;        Statement last = null;&lt;br /&gt;        HashMap&amp;lt;String,Statement&amp;gt; labels = new HashMap&amp;lt;String,Statement&amp;gt;();&lt;br /&gt;        for (; index &amp;lt; args.length; index++)&lt;br /&gt;            for (Statement s : new Parser(args[index])) {&lt;br /&gt;                if (first == null)&lt;br /&gt;                    s = first = new FirstStatement(s, encodeOutput);&lt;br /&gt;                else if (last != null)&lt;br /&gt;                    last.setNext(s);&lt;br /&gt;                last = s;&lt;br /&gt;                if (s.getLabel() != null) {&lt;br /&gt;                    if (labels.containsKey(s.getLabel()))&lt;br /&gt;                        throw new RESOLException(s, "DUPLICATE LABEL");&lt;br /&gt;                    labels.put(s.getLabel(), s);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        last = first;&lt;br /&gt;        while (last != null)&lt;br /&gt;            last = last.run(labels);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-7814581347091131200?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/7814581347091131200/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/04/here-is-resol-interpreter-in-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7814581347091131200'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7814581347091131200'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/04/here-is-resol-interpreter-in-java.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-7569816598562213066</id><published>2010-03-29T00:00:00.000-07:00</published><updated>2010-03-29T00:00:03.409-07:00</updated><title type='text'></title><content type='html'>Here is a &lt;a href="/2009/12/resol-programming-language.html"&gt;RESOL&lt;/a&gt; program that prints itself.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;001   DATA1&lt;br /&gt;      DATA001,99999&lt;br /&gt;      CALL004,99999&lt;br /&gt;      CALL10000,0010&lt;br /&gt;      CALL10002&lt;br /&gt;      CALL002&lt;br /&gt;      STOP&lt;br /&gt;002   DATA1&lt;br /&gt;      DATA002&lt;br /&gt;      DATA002,10001&lt;br /&gt;      DATA001,10001&lt;br /&gt;      DATA10001&lt;br /&gt;      CONTINUE002&lt;br /&gt;004   DATA000066&lt;br /&gt;      CALL005,004&lt;br /&gt;      DATA004&lt;br /&gt;      CONTINUE004&lt;br /&gt;005   DATA1&lt;br /&gt;      CALL10000,0010020002000200020002000211&lt;br /&gt;006   IF005,0&lt;br /&gt;      CALL10000,0300&lt;br /&gt;      IF005,1&lt;br /&gt;      CALL10000,0301&lt;br /&gt;      IF005,2&lt;br /&gt;      CALL10000,0302&lt;br /&gt;      IF005,3&lt;br /&gt;      CALL10000,0303&lt;br /&gt;      IF005,4&lt;br /&gt;      CALL10000,0304&lt;br /&gt;      IF005,5&lt;br /&gt;      CALL10000,0305&lt;br /&gt;      IF005,6&lt;br /&gt;      CALL10000,0306&lt;br /&gt;      IF005,7&lt;br /&gt;      CALL10000,0307&lt;br /&gt;      CALL002&lt;br /&gt;      DATA005&lt;br /&gt;      CONTINUE005,006&lt;br /&gt;C THIS IS A LIBRARY THAT CONVERTS 4-BIT ITEMS ENQUEUED INTO 10000 AS 2 DIGITS&lt;br /&gt;C INTO 3-BIT ITEMS IN 1 DIGIT THAT ARE AVAILABLE AT 10001.&lt;br /&gt;C CALL 10000 TO PROCESS ITEMS FROM 10000 INTO 10001.&lt;br /&gt;C CALL 10002 TO FLUSH THE FINAL DANGLING BITS (0-2 BITS).&lt;br /&gt;C IF 000002 IS A DATA STATEMENT, CALLING 10000 WILL DEQUEUE FROM IT.  BEST&lt;br /&gt;C NOT TO HAVE 000002 AS A LABEL (WHICH WOULD REQUIRE A CONTINUATION LINE).&lt;br /&gt;10000 DATA 000002&lt;br /&gt;      IF 10003,11000&lt;br /&gt;      CALL 10100&lt;br /&gt;      IF 10003,11001&lt;br /&gt;      CALL 10110&lt;br /&gt;      IF 10003,11002&lt;br /&gt;      CALL 10120&lt;br /&gt;      DATA 10003&lt;br /&gt;      DATA 10000&lt;br /&gt;      CONTINUE 10000&lt;br /&gt;10001 DATA 1&lt;br /&gt;C FLUSH THE FINAL DANGLING BITS&lt;br /&gt;10002 IF 10003,11000&lt;br /&gt;      CONTINUE 10002&lt;br /&gt;      DATA 10001,10004&lt;br /&gt;      DATA 10004&lt;br /&gt;C REINITIALIZE 10003 TO 012&lt;br /&gt;      IF 10003,11001&lt;br /&gt;      DATA 10003&lt;br /&gt;      DATA 10003&lt;br /&gt;      DATA 10003,012&lt;br /&gt;      CONTINUE 10002&lt;br /&gt;C 10003 HOLDS THE NUMBER OF DANGLING BITS&lt;br /&gt;10003 DATA 1,012&lt;br /&gt;C 10004 HOLDS THE VALUE OF THE DANGLING BITS&lt;br /&gt;10004 DATA 1&lt;br /&gt;C NO DANGLING BITS FROM BEFORE.  LEAVES 1 DANGLING BIT FOR NEXT ITEM.&lt;br /&gt;10100 IF 10000,12000&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12000&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      CONTINUE 10100&lt;br /&gt;C 1 DANGLING BIT FROM BEFORE.  LEAVES 2 DANGLING BITS FOR NEXT ITEM.&lt;br /&gt;10110 IF 10004,11000&lt;br /&gt;      CALL 10111&lt;br /&gt;      IF 10004,11004&lt;br /&gt;      CALL 10112&lt;br /&gt;      DATA 10004&lt;br /&gt;      CONTINUE 10110&lt;br /&gt;C DANGLING 0 FROM BEFORE&lt;br /&gt;10111 IF 10000,12000&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12000&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      CONTINUE 10111&lt;br /&gt;C DANGLING 1 FROM BEFORE&lt;br /&gt;10112 IF 10000,12000&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12000&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      CONTINUE 10112&lt;br /&gt;C 2 DANGLING BITS FROM BEFORE.  LEAVES NO DANGLING BITS FOR NEXT ITEM.&lt;br /&gt;10120 IF 10004,11000&lt;br /&gt;      CALL 10121&lt;br /&gt;      IF 10004,11002&lt;br /&gt;      CALL 10122&lt;br /&gt;      IF 10004,11004&lt;br /&gt;      CALL 10123&lt;br /&gt;      IF 10004,11006&lt;br /&gt;      CALL 10124&lt;br /&gt;      DATA 10003,13012&lt;br /&gt;      DATA 10004&lt;br /&gt;      IF 10000,12000&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      CONTINUE 10120&lt;br /&gt;C DANGLING 00 FROM BEFORE&lt;br /&gt;10121 IF 10000,12000&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      CONTINUE 10121&lt;br /&gt;C DANGLING 01 FROM BEFORE&lt;br /&gt;10122 IF 10000,12000&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      CONTINUE 10122&lt;br /&gt;C DANGLING 10 FROM BEFORE&lt;br /&gt;10123 IF 10000,12000&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      CONTINUE 10123&lt;br /&gt;C DANGLING 11 FROM BEFORE&lt;br /&gt;10124 IF 10000,12000&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      CONTINUE 10124&lt;br /&gt;C CONSTANTS&lt;br /&gt;11000 DATA 1,0&lt;br /&gt;11001 DATA 1,1&lt;br /&gt;11002 DATA 1,2&lt;br /&gt;11003 DATA 1,3&lt;br /&gt;11004 DATA 1,4&lt;br /&gt;11005 DATA 1,5&lt;br /&gt;11006 DATA 1,6&lt;br /&gt;11007 DATA 1,7&lt;br /&gt;12000 DATA 2,00&lt;br /&gt;12001 DATA 2,01&lt;br /&gt;12002 DATA 2,02&lt;br /&gt;12003 DATA 2,03&lt;br /&gt;12004 DATA 2,04&lt;br /&gt;12005 DATA 2,05&lt;br /&gt;12006 DATA 2,06&lt;br /&gt;12007 DATA 2,07&lt;br /&gt;12008 DATA 2,08&lt;br /&gt;12009 DATA 2,09&lt;br /&gt;12010 DATA 2,10&lt;br /&gt;12011 DATA 2,11&lt;br /&gt;12012 DATA 2,12&lt;br /&gt;12013 DATA 2,13&lt;br /&gt;12014 DATA 2,14&lt;br /&gt;12015 DATA 2,15&lt;br /&gt;13012 DATA 3,012&lt;br /&gt;99999 DATA 40000,&lt;br /&gt;     +140300611002004021040524202304121002004010020040210405242023006014&lt;br /&gt;     +226071162344711620504010020040100201032024611414030064130344711623&lt;br /&gt;     +447102420040100200401004150123046061140300601402606014030460024200&lt;br /&gt;     +401002004010041501230460611403006014405040100200401002010320246114&lt;br /&gt;     +140300620242004010020040100515242365001214030062100200402104052420&lt;br /&gt;     +230412100200401002004021040524202300601440504010020040100201042025&lt;br /&gt;     +210114030062130304601403006102420040100200401004210125040460140304&lt;br /&gt;     +541423006014030412100200401002004021040524202304601403006102420040&lt;br /&gt;     +100200401004151723452111234525051403006202430060150200401004210125&lt;br /&gt;     +040460140300601543301210020040100200402064051423030060152260601403&lt;br /&gt;     +201210020040100200402104052420230060150050401002004010020103236471&lt;br /&gt;     +242224712521230060150050601403244010020104202521011420504010020040&lt;br /&gt;     +100201032024611414230060140300541403006114030062140300601443006014&lt;br /&gt;     +031060140300621403006014430060140310611420506014033040100201112143&lt;br /&gt;     +006015226060024200401002004010041501230460611403006014026060146300&lt;br /&gt;     +600242004010020040100445061403006513030412100200401002004020640514&lt;br /&gt;     +230304601403006013030063140304121002004010020040222430601403245414&lt;br /&gt;     +405040100200401002010320246114142300601403005414031460144050401002&lt;br /&gt;     +004010020111214300601522606302420040100200401004150123046061140300&lt;br /&gt;     +601402606014630063024200401002004010044506140300651303201210020040&lt;br /&gt;     +100200402064051423030460140300601303006314032012100200401002004022&lt;br /&gt;     +243060140324541520504010020040100201032024611414230060140300541403&lt;br /&gt;     +146015205040100200401002011121430060152260660242004010020040100415&lt;br /&gt;     +012304606114030060140260601463006602420040100200401004450614030065&lt;br /&gt;     +130334121002004010020040206405142303046014030060130300631403341210&lt;br /&gt;     +020040100200402064051423030060144050401002004010020104202521011403&lt;br /&gt;     +006502420040100200401004151723452111234525051403006513030060154051&lt;br /&gt;     +031005211022251440222514402022011422241122202511311005211020252040&lt;br /&gt;     +206475162544252225051440150265022225204022252105232514402124712125&lt;br /&gt;     +242525212420402224712423620061140300601402010124620062100421112164&lt;br /&gt;     +452424605103100445162504744014626502222520402225210523251440222470&lt;br /&gt;     +401422010422243511250201242204052410040522212201012544051123040502&lt;br /&gt;     +230424402025204014230060140304560244144020640514230200611403006014&lt;br /&gt;     +020124236201202444750321251523100445242124652310043122236464401423&lt;br /&gt;     +006014030040222471242362006114030060142270122062010320246114100304&lt;br /&gt;     +601403006210052117100431142525151010052110212201062224710123020104&lt;br /&gt;     +202471072304451621620102222521231002406013231040204445242462445602&lt;br /&gt;     +441440222430401403006014030062100445231004044021040524202201232504&lt;br /&gt;     +052421246505234520541004150123046111234434401423006014030040256445&lt;br /&gt;     +142302010421250525212525051004312223646440222520561002010221251524&lt;br /&gt;     +024414402344752410052117100441012544244014030060140300621004052310&lt;br /&gt;     +040440230405022124604012053510222415101005351725246104100511052425&lt;br /&gt;     +251124442440202201032364712422247125202521112364704023044516212244&lt;br /&gt;     +560243046014030060100421012504044014030060140300620242004010020040&lt;br /&gt;     +100445061003046014030063130304611403006002420040100200401004150123&lt;br /&gt;     +046040142300611403001210020040100200402224304014230060140314541423&lt;br /&gt;     +046014030412100200401002004020640514230200611403046114005040100200&lt;br /&gt;     +401002011121420061140300601462606114230060144050401002004010020103&lt;br /&gt;     +202461141003046014231060024200401002004010042101250404401423006014&lt;br /&gt;     +031412100200401002004021040524202200611403006014005040100200401002&lt;br /&gt;     +010323647124222471252122006114030060140050611403006014220104202521&lt;br /&gt;     +011003041220620106230525232202012422042440214445162024604021040516&lt;br /&gt;     +216461112344344020444524246050611403006014420111214200611403006014&lt;br /&gt;     +626061142300601400504010020040100201032364712422247125212200611403&lt;br /&gt;     +006014405040100200401002010420252101100304601403006113030460140300&lt;br /&gt;     +640242004010020040100421012504044014230060140320122062012221244516&lt;br /&gt;     +222521112024611126442440142300601403144025047440140304620242004010&lt;br /&gt;     +020040100445061003046014030063130304611403006102420040100200401004&lt;br /&gt;     +210125040440142300601403141210020040100200402104052420220061140300&lt;br /&gt;     +601460504010020040100201042025210110030460140300631303006114405040&lt;br /&gt;     +100200401002010323647124222471252122006114030060144051031003046014&lt;br /&gt;     +030063100441172304212310052110212201162524650221251040236430402104&lt;br /&gt;     +051621646111234434402044452424605061140300601462010420252101100304&lt;br /&gt;     +541403046202441440142300601403204022047514210514402504410510053101&lt;br /&gt;     +230525051004750610052110212201042024710723044516216201022225212302&lt;br /&gt;     +430460140300641004210125040440142051031004711710042101234435142224&lt;br /&gt;     +710710041111250514402145111723220102212431172444245610020114212405&lt;br /&gt;     +262125144014220104202471072304451621620102222520402144752210047105&lt;br /&gt;     +260520402225210523227012142300611403004022243040142300601403005414&lt;br /&gt;     +231060140300121002004010020040210405242022006114030060142260611423&lt;br /&gt;     +006014005040100200401002011121420061140300601402606114430060140050&lt;br /&gt;     +401002004010020104202521011003046014030064130304611403006002420040&lt;br /&gt;     +100200401004450610030460140300601303046214030061024200401002004010&lt;br /&gt;     +042101250404401423006014030454142304601403001210020040100200402224&lt;br /&gt;     +304014230060140300541423106014030412100200401002004021040524202200&lt;br /&gt;     +611403006015026061142300601500504010020040100201112142006114030060&lt;br /&gt;     +140260611443006014405040100200401002010420252101100304601403006113&lt;br /&gt;     +030461140300610242004010020040100445061003046014030060130304621403&lt;br /&gt;     +006202420040100200401004210125040440142300601403205414230460140300&lt;br /&gt;     +121002004010020040222430401423006014030054142310601403141210020040&lt;br /&gt;     +100200402104052420220061140300601422606114230060142050401002004010&lt;br /&gt;     +020111214200611403006014026061144300601460504010020040100201042025&lt;br /&gt;     +210110030460140300641303046114030064024200401002004010044506100304&lt;br /&gt;     +601403006013030462140300640242004010020040100421012504044014230060&lt;br /&gt;     +140304541423046014031012100200401002004022243040142300601403005414&lt;br /&gt;     +231060140320121002004010020040210405242022006114030060150260611423&lt;br /&gt;     +006014005040100200401002011121420061140300601402606114430060152050&lt;br /&gt;     +401002004010020104202521011003046014030061130304611403006202420040&lt;br /&gt;     +100200401004450610030460140300601303046214030065024200401002004010&lt;br /&gt;     +042101250404401423006014032054142304601403201210020040100200402224&lt;br /&gt;     +304014230060140300541423106014033012100200401002004021040524202200&lt;br /&gt;     +611403006014226061142300601460504010020040100201112142006114030060&lt;br /&gt;     +140260611443006015405040100200401002010420252101100304601403006413&lt;br /&gt;     +030461140300600242004010020040100445061003046014030060130304621403&lt;br /&gt;     +006702420040100200401004210125040440142300601403045414230460140314&lt;br /&gt;     +121002004010020040222430401423006014030054142310601403341210020040&lt;br /&gt;     +100200402104052420220061140300601502606114230060150050401002004010&lt;br /&gt;     +020111214200611403006014026061144300601600504010020040100201042025&lt;br /&gt;     +210110030460140300611303046114030064024200401002004010044506100304&lt;br /&gt;     +601403006013030462140300700242004010020040100421012504044014230060&lt;br /&gt;     +140320541423046014030012100200401002004022243040142300601403005414&lt;br /&gt;     +231060140344121002004010020040210405242022006114030060142260611423&lt;br /&gt;     +006015005040100200401002011121420061140300601402606114430060162050&lt;br /&gt;     +401002004010020104202521011003046014030064130304611403006402420040&lt;br /&gt;     +100200401004450610030460140300601303046214030460024200401002004010&lt;br /&gt;     +042101250404401423006014030454142304601403241210020040100200402224&lt;br /&gt;     +304014230060140300541423106014230012100200401002004021040524202200&lt;br /&gt;     +611403006015026061142300601400504010020040100201112142006114030060&lt;br /&gt;     +140260611443006114205040100200401002010420252101100304601403006113&lt;br /&gt;     +030461140300650242004010020040100445061003046014030060130304621403&lt;br /&gt;     +046102420040100200401004210125040440142300601403205414230460140320&lt;br /&gt;     +121002004010020040222430401423006014030054142310601423101210020040&lt;br /&gt;     +100200402104052420220061140300601422606114230060154050401002004010&lt;br /&gt;     +020111214200611403006014026061144300611440504010020040100201042025&lt;br /&gt;     +210110030460140300641303046114030060024200401002004010044506100304&lt;br /&gt;     +601403006013030462140304630242004010020040100421012504044014230060&lt;br /&gt;     +140304541423046014033012100200401002004022243040142300601403005414&lt;br /&gt;     +231060142314121002004010020040210405242022006114030060150260611423&lt;br /&gt;     +006015005040100200401002011121420061140300601402606114430061150050&lt;br /&gt;     +401002004010020104202521011003046014030061130304611403006702420040&lt;br /&gt;     +100200401004450610030460140300601303046214030464024200401002004010&lt;br /&gt;     +042101250404401423006014032054142304601403001210020040100200402224&lt;br /&gt;     +304014230060140300541423106014232412100200401002004021040524202200&lt;br /&gt;     +611403006014226061142300601560504010020040100201112142006114030060&lt;br /&gt;     +140260611443006115205040100200401002010420252101100304601403006413&lt;br /&gt;     +030461140300640242004010020040100415172345211123452505100304601423&lt;br /&gt;     +006002441440142201042024710723044516216201022225204021451117232201&lt;br /&gt;     +022124311724442456100201142124052621251440144201042024710723044516&lt;br /&gt;     +216201022225212310043117244201162125412410044524212464560243046014&lt;br /&gt;     +230460100445061003046014030064130304611403006002420040100200401004&lt;br /&gt;     +150123046040142300611423041210020040100200402224304014230060140320&lt;br /&gt;     +541423046014032012100200401002004020640514230200611403046114405040&lt;br /&gt;     +100200401002010420252101100304601403006402420040100200401004151723&lt;br /&gt;     +452111234525051003046014230460024414402104051621646111234434401402&lt;br /&gt;     +010624447515100411052144752221205061140304611422011121420061140300&lt;br /&gt;     +601402606114430060140050401002004010020104202521011003046014030061&lt;br /&gt;     +130304611403006002420040100200401004450610030460140300601303046214&lt;br /&gt;     +030060024200401002004010042101250404401423006014032054142304601403&lt;br /&gt;     +001210020040100200402224304014230060140300541423106014030412100200&lt;br /&gt;     +401002004021040524202200611403006014226061142300601400504010020040&lt;br /&gt;     +100201112142006114030060140260611443006014205040100200401002010420&lt;br /&gt;     +252101100304601403006413030461140300620242004010020040100445061003&lt;br /&gt;     +046014030060130304621403006202420040100200401004210125040440142300&lt;br /&gt;     +601403045414230460140300121002004010020040222430401423006014030054&lt;br /&gt;     +142310601403101210020040100200402104052420220061140300601502606114&lt;br /&gt;     +230060150050401002004010020111214200611403006014026061144300601460&lt;br /&gt;     +504010020040100201042025210110030460140300611303046114030060024200&lt;br /&gt;     +401002004010044506100304601403006013030462140300630242004010020040&lt;br /&gt;     +100421012504044014230060140320541423046014033012100200401002004022&lt;br /&gt;     +243040142300601403005414231060140320121002004010020040210405242022&lt;br /&gt;     +006114030060142260611423006014205040100200401002011121420061140300&lt;br /&gt;     +601402606114430060150050401002004010020104202521011003046014030064&lt;br /&gt;     +130304611403006002420040100200401004450610030460140300601303046214&lt;br /&gt;     +030065024200401002004010042101250404401423006014030454142304601403&lt;br /&gt;     +041210020040100200402224304014230060140300541423106014032412100200&lt;br /&gt;     +401002004021040524202200611403006015026061142300601440504010020040&lt;br /&gt;     +100201112142006114030060140260611443006015405040100200401002010420&lt;br /&gt;     +252101100304601403006113030461140300610242004010020040100445061003&lt;br /&gt;     +046014030060130304621403006602420040100200401004210125040440142300&lt;br /&gt;     +601403205414230460140320121002004010020040222430401423006014030054&lt;br /&gt;     +142310601403341210020040100200402104052420220061140300601422606114&lt;br /&gt;     +230060142050401002004010020111214200611403006014026061144300601560&lt;br /&gt;     +504010020040100201042025210110030460140300641303046114030066024200&lt;br /&gt;     +401002004010044506100304601403006013030462140300700242004010020040&lt;br /&gt;     +100421012504044014230060140304541423046014031012100200401002004022&lt;br /&gt;     +243040142300601403005414231060140340121002004010020040210405242022&lt;br /&gt;     +006114030060150260611423006014005040100200401002011121420061140300&lt;br /&gt;     +601402606114430060162050401002004010020104202521011003046014030061&lt;br /&gt;     +130304611403006202420040100200401004450610030460140300601303046214&lt;br /&gt;     +030071024200401002004010042101250404401423006014032054142304601403&lt;br /&gt;     +101210020040100200402224304014230060140300541423106014230012100200&lt;br /&gt;     +401002004021040524202200611403006014226061142300601440504010020040&lt;br /&gt;     +100201112142006114030060140260611443006114005040100200401002010420&lt;br /&gt;     +252101100304601403006413030461140300640242004010020040100445061003&lt;br /&gt;     +046014030060130304621403046102420040100200401004210125040440142300&lt;br /&gt;     +601403045414230460140310121002004010020040222430401423006014030054&lt;br /&gt;     +142310601423041210020040100200402104052420220061140300601502606114&lt;br /&gt;     +230060154050401002004010020111214200611403006014026061144300611440&lt;br /&gt;     +504010020040100201042025210110030460140300611303046114030063024200&lt;br /&gt;     +401002004010044506100304601403006013030462140304620242004010020040&lt;br /&gt;     +100421012504044014230060140320541423046014030012100200401002004022&lt;br /&gt;     +243040142300601403005414231060142314121002004010020040210405242022&lt;br /&gt;     +006114030060142260611423006014605040100200401002011121420061140300&lt;br /&gt;     +601402606114430061146050401002004010020104202521011003046014030064&lt;br /&gt;     +130304611403006202420040100200401004450610030460140300601303046214&lt;br /&gt;     +030464024200401002004010042101250404401423006014030454142304601403&lt;br /&gt;     +141210020040100200402224304014230060140300541423106014232012100200&lt;br /&gt;     +401002004021040524202200611403006015026061142300601500504010020040&lt;br /&gt;     +100201112142006114030060140260611443006115205040100200401002010420&lt;br /&gt;     +252101100304601403006113030461140300630242004010020040100445061003&lt;br /&gt;     +046014030060130304621403046502420040100200401004210125040440142300&lt;br /&gt;     +601403205414230460140330121002004010020040206475162504451625242440&lt;br /&gt;     +142300611423041220620104202471072304451621620061100431222364644020&lt;br /&gt;     +442506236511050243046014230462100445061003046014030060130304621403&lt;br /&gt;     +006002420040100200401004210125040440142300601403045414230460140320&lt;br /&gt;     +121002004010020040222430401423006014030054142310601403001210020040&lt;br /&gt;     +100200402104052420220061140300601502606114230060140050401002004010&lt;br /&gt;     +020111214200611403006014026061144300601420504010020040100201042025&lt;br /&gt;     +210110030460140300611303046114030064024200401002004010044506100304&lt;br /&gt;     +601403006013030462140300610242004010020040100421012504044014230060&lt;br /&gt;     +140320541423046014031012100200401002004022243040142300601403005414&lt;br /&gt;     +231060140310121002004010020040210405242022006114030060142260611423&lt;br /&gt;     +006015005040100200401002011121420061140300601402606114430060144050&lt;br /&gt;     +401002004010020104202521011003046014030064130304611403006402420040&lt;br /&gt;     +100200401004450610030460140300601303046214030063024200401002004010&lt;br /&gt;     +042101250404401423006014030454142304601403201210020040100200402224&lt;br /&gt;     +304014230060140300541423106014031412100200401002004021040524202200&lt;br /&gt;     +611403006015026061142300601540504010020040100201112142006114030060&lt;br /&gt;     +140260611443006015005040100200401002010420252101100304601403006113&lt;br /&gt;     +030461140300650242004010020040100445061003046014030060130304621403&lt;br /&gt;     +006402420040100200401004210125040440142300601403205414230460140300&lt;br /&gt;     +121002004010020040222430401423006014030054142310601403241210020040&lt;br /&gt;     +100200402104052420220061140300601422606114230060152050401002004010&lt;br /&gt;     +020111214200611403006014026061144300601520504010020040100201042025&lt;br /&gt;     +210110030460140300641303046114030062024200401002004010044506100304&lt;br /&gt;     +601403006013030462140300660242004010020040100421012504044014230060&lt;br /&gt;     +140304541423046014032412100200401002004022243040142300601403005414&lt;br /&gt;     +231060140330121002004010020040210405242022006114030060150260611423&lt;br /&gt;     +006015005040100200401002011121420061140300601402606114430060156050&lt;br /&gt;     +401002004010020104202521011003046014030061130304611403006502420040&lt;br /&gt;     +100200401004450610030460140300601303046214030067024200401002004010&lt;br /&gt;     +042101250404401423006014032054142304601403301210020040100200402224&lt;br /&gt;     +304014230060140300541423106014034012100200401002004021040524202200&lt;br /&gt;     +611403006014226061142300601540504010020040100201112142006114030060&lt;br /&gt;     +140260611443006016005040100200401002010420252101100304601403006413&lt;br /&gt;     +030461140300600242004010020040100445061003046014030060130304621403&lt;br /&gt;     +007102420040100200401004210125040440142300601403045414230460140330&lt;br /&gt;     +121002004010020040222430401423006014030054142310601403441210020040&lt;br /&gt;     +100200402104052420220061140300601502606114230060144050401002004010&lt;br /&gt;     +020111214200611403006014026061144300611400504010020040100201042025&lt;br /&gt;     +210110030460140300611303046114030066024200401002004010044506100304&lt;br /&gt;     +601403006013030462140304600242004010020040100421012504044014230060&lt;br /&gt;     +140320541423046014032012100200401002004022243040142300601403005414&lt;br /&gt;     +231060142304121002004010020040210405242022006114030060142260611423&lt;br /&gt;     +006015405040100200401002011121420061140300601402606114430061142050&lt;br /&gt;     +401002004010020104202521011003046014030064130304611403006602420040&lt;br /&gt;     +100200401004450610030460140300601303046214030462024200401002004010&lt;br /&gt;     +042101250404401423006014030454142304601403341210020040100200402224&lt;br /&gt;     +304014230060140300541423106014231012100200401002004021040524202200&lt;br /&gt;     +611403006015026061142300601400504010020040100201112142006114030060&lt;br /&gt;     +140260611443006114605040100200401002010420252101100304601403006113&lt;br /&gt;     +030461140300670242004010020040100445061003046014030060130304621403&lt;br /&gt;     +046302420040100200401004210125040440142300601403205414230460140310&lt;br /&gt;     +121002004010020040222430401423006014030054142310601423201210020040&lt;br /&gt;     +100200402104052420220061140300601422606114230060156050401002004010&lt;br /&gt;     +020111214200611403006014026061144300611500504010020040100201042025&lt;br /&gt;     +210110030460140300641303046114030064024200401002004010044506100304&lt;br /&gt;     +601403006013030462140304650242004010020040100421012504044014230060&lt;br /&gt;     +140304541423046014033412100200401002004022243040142300601403005414&lt;br /&gt;     +231060142324121002004010020040210405242022006114030060150260611423&lt;br /&gt;     +006015405040100200401002010323647124222471252122006114030461144051&lt;br /&gt;     +031003104021040516216461112344344020444524246201062444751510041105&lt;br /&gt;     +214475222122704010046105202531052462011623620104202471072304451621&lt;br /&gt;     +620102222521231004311724420116212541241004452421246456024304601423&lt;br /&gt;     +106010044506100304601403006413030461140300600242004010020040100415&lt;br /&gt;     +012304604014230061144304121002004010020040222430401423006014032054&lt;br /&gt;     +142304601403101210020040100200402064051423020061140304621440504010&lt;br /&gt;     +020040100201112142006114030060150260611423006015005040100200401002&lt;br /&gt;     +010320246114100304601423106302420040100200401004450610030460140300&lt;br /&gt;     +641303046114030066024200401002004010041501230460401423006114432012&lt;br /&gt;     +100200401002004021040524202200611403006014626061146300611440504010&lt;br /&gt;     +020040100201042025210110030460140300640242004010020040100445061003&lt;br /&gt;     +046014030060130304621403006002420040100200401004210125040440142300&lt;br /&gt;     +601403045414230460140300121002004010020040222430401423006014030054&lt;br /&gt;     +142310601403041210020040100200402104052420220061140300601422606114&lt;br /&gt;     +230060142050401002004010020111214200611403006014026061144300601440&lt;br /&gt;     +504010020040100201042025210110030460140300611303046114030062024200&lt;br /&gt;     +401002004010044506100304601403006013030462140300630242004010020040&lt;br /&gt;     +100421012504044014230060140304541423046014031412100200401002004022&lt;br /&gt;     +243040142300601403005414231060140320121002004010020040210405242022&lt;br /&gt;     +006114030060142260611423006015005040100200401002011121420061140300&lt;br /&gt;     +601402606114430060152050401002004010020104202521011003046014030061&lt;br /&gt;     +130304611403006502420040100200401004450610030460140300601303046214&lt;br /&gt;     +030066024200401002004010042101250404401423006014030454142304601403&lt;br /&gt;     +301210020040100200402224304014230060140300541423106014033412100200&lt;br /&gt;     +401002004021040524202200611403006014226061142300601560504010020040&lt;br /&gt;     +100201112142006114030060140260611443006016005040100200401002010420&lt;br /&gt;     +252101100304601403006113030461140300600242004010020040100445061003&lt;br /&gt;     +046014030060130304621403007102420040100200401004210125040440142300&lt;br /&gt;     +601403045414230460140304121002004010020040222430401423006014030054&lt;br /&gt;     +142310601423001210020040100200402104052420220061140300601422606114&lt;br /&gt;     +230060144050401002004010020111214200611403006014026061144300611420&lt;br /&gt;     +504010020040100201042025210110030460140300611303046114030063024200&lt;br /&gt;     +401002004010044506100304601403006013030462140304620242004010020040&lt;br /&gt;     +100421012504044014230060140304541423046014032012100200401002004022&lt;br /&gt;     +243040142300601403005414231060142314121002004010020040210405242022&lt;br /&gt;     +006114030060142260611423006015205040100200401002011121420061140300&lt;br /&gt;     +601402606114430061150050401002004010020104202521011003046014030061&lt;br /&gt;     +130304611403006602420040100200401004450610030460140300601303046214&lt;br /&gt;     +030465024200401002004010042101250404401423006014030454142304601403&lt;br /&gt;     +341210020040100200402064751625044516252424401423006114430012206201&lt;br /&gt;     +042024710723044516216200601402010624447515100411052144752221205061&lt;br /&gt;     +140304621422011121420061140300601402606114430060140050401002004010&lt;br /&gt;     +020104202521011003046014030061130304611403006002420040100200401004&lt;br /&gt;     +450610030460140300601303046214030061024200401002004010042101250404&lt;br /&gt;     +401423006014030454142304601403001210020040100200402224304014230060&lt;br /&gt;     +140300541423106014031012100200401002004021040524202200611403006014&lt;br /&gt;     +226061142300601400504010020040100201112142006114030060140260611443&lt;br /&gt;     +006014605040100200401002010420252101100304601403006113030461140300&lt;br /&gt;     +600242004010020040100445061003046014030060130304621403006402420040&lt;br /&gt;     +100200401004210125040440142300601403045414230460140300121002004010&lt;br /&gt;     +020040222430401423006014030054142310601403241210020040100200402104&lt;br /&gt;     +052420220061140300601422606114230060140050401002004010020111214200&lt;br /&gt;     +611403006014026061144300601540504010020040100201042025210110030460&lt;br /&gt;     +140300611303046114030060024200401002004010044506100304601403006013&lt;br /&gt;     +030462140300670242004010020040100421012504044014230060140304541423&lt;br /&gt;     +046014030012100200401002004022243040142300601403005414231060140340&lt;br /&gt;     +121002004010020040210405242022006114030060142260611423006014205040&lt;br /&gt;     +100200401002011121420061140300601402606114430060162050401002004010&lt;br /&gt;     +020104202521011003046014030061130304611403006102420040100200401004&lt;br /&gt;     +450610030460140300601303046214030460024200401002004010042101250404&lt;br /&gt;     +401423006014030454142304601403041210020040100200402224304014230060&lt;br /&gt;     +140300541423106014230412100200401002004021040524202200611403006014&lt;br /&gt;     +226061142300601420504010020040100201112142006114030060140260611443&lt;br /&gt;     +006114405040100200401002010420252101100304601403006113030461140300&lt;br /&gt;     +610242004010020040100445061003046014030060130304621403046302420040&lt;br /&gt;     +100200401004210125040440142300601403045414230460140304121002004010&lt;br /&gt;     +020040222430401423006014030054142310601423201210020040100200402104&lt;br /&gt;     +052420220061140300601422606114230060142050401002004010020111214200&lt;br /&gt;     +611403006014026061144300611520504010020040100201042025210110030460&lt;br /&gt;     +140300611303046114030061024200401002004010041517234521112345250510&lt;br /&gt;     +030460142310610244144021040516216461112344344014030440214511172322&lt;br /&gt;     +010221243117244424121423006114431040222430401423006014030054142310&lt;br /&gt;     +601403001210020040100200402104052420220061140300601422606114230060&lt;br /&gt;     +144050401002004010020111214200611403006014026061144300601420504010&lt;br /&gt;     +020040100201042025210110030460140300611303046114030062024200401002&lt;br /&gt;     +004010044506100304601403006013030462140300620242004010020040100421&lt;br /&gt;     +012504044014230060140304541423046014031012100200401002004022243040&lt;br /&gt;     +142300601403005414231060140314121002004010020040210405242022006114&lt;br /&gt;     +030060142260611423006014405040100200401002011121420061140300601402&lt;br /&gt;     +606114430060150050401002004010020104202521011003046014030061130304&lt;br /&gt;     +611403006202420040100200401004450610030460140300601303046214030065&lt;br /&gt;     +024200401002004010042101250404401423006014030454142304601403101210&lt;br /&gt;     +020040100200402224304014230060140300541423106014033012100200401002&lt;br /&gt;     +004021040524202200611403006014226061142300601440504010020040100201&lt;br /&gt;     +112142006114030060140260611443006015605040100200401002010420252101&lt;br /&gt;     +100304601403006113030461140300620242004010020040100445061003046014&lt;br /&gt;     +030060130304621403007002420040100200401004210125040440142300601403&lt;br /&gt;     +045414230460140314121002004010020040222430401423006014030054142310&lt;br /&gt;     +601403441210020040100200402104052420220061140300601422606114230060&lt;br /&gt;     +146050401002004010020111214200611403006014026061144300611400504010&lt;br /&gt;     +020040100201042025210110030460140300611303046114030063024200401002&lt;br /&gt;     +004010044506100304601403006013030462140304610242004010020040100421&lt;br /&gt;     +012504044014230060140304541423046014031412100200401002004022243040&lt;br /&gt;     +142300601403005414231060142310121002004010020040210405242022006114&lt;br /&gt;     +030060142260611423006014605040100200401002011121420061140300601402&lt;br /&gt;     +606114430061146050401002004010020104202521011003046014030061130304&lt;br /&gt;     +611403006302420040100200401004450610030460140300601303046214030464&lt;br /&gt;     +024200401002004010042101250404401423006014030454142304601403141210&lt;br /&gt;     +020040100200402224304014230060140300541423106014232412100200401002&lt;br /&gt;     +004021040524202200611403006014226061142300601460504010020040100201&lt;br /&gt;     +032364712422247125212200611403046214405103100421012344351422247107&lt;br /&gt;     +100304601004312223646440204425062365110502430460142310631004450610&lt;br /&gt;     +030460140300601303046214030060024200401002004010042101250404401423&lt;br /&gt;     +006014030454142304601403201210020040100200402224304014230060140300&lt;br /&gt;     +541423106014030412100200401002004021040524202200611403006014226061&lt;br /&gt;     +142300601500504010020040100201112142006114030060140260611443006014&lt;br /&gt;     +405040100200401002010420252101100304601403006113030461140300640242&lt;br /&gt;     +004010020040100445061003046014030060130304621403006302420040100200&lt;br /&gt;     +401004210125040440142300601403045414230460140320121002004010020040&lt;br /&gt;     +222430401423006014030054142310601403201210020040100200402104052420&lt;br /&gt;     +220061140300601422606114230060150050401002004010020111214200611403&lt;br /&gt;     +006014026061144300601520504010020040100201042025210110030460140300&lt;br /&gt;     +611303046114030064024200401002004010044506100304601403006013030462&lt;br /&gt;     +140300660242004010020040100421012504044014230060140304541423046014&lt;br /&gt;     +032012100200401002004022243040142300601403005414231060140334121002&lt;br /&gt;     +004010020040210405242022006114030060142260611423006015005040100200&lt;br /&gt;     +401002011121420061140300601402606114430060160050401002004010020104&lt;br /&gt;     +202521011003046014030061130304611403006502420040100200401004450610&lt;br /&gt;     +030460140300601303046214030071024200401002004010042101250404401423&lt;br /&gt;     +006014030454142304601403241210020040100200402224304014230060140300&lt;br /&gt;     +541423106014230012100200401002004021040524202200611403006014226061&lt;br /&gt;     +142300601520504010020040100201112142006114030060140260611443006114&lt;br /&gt;     +205040100200401002010420252101100304601403006113030461140300650242&lt;br /&gt;     +004010020040100445061003046014030060130304621403046202420040100200&lt;br /&gt;     +401004210125040440142300601403045414230460140324121002004010020040&lt;br /&gt;     +222430401423006014030054142310601423141210020040100200402104052420&lt;br /&gt;     +220061140300601422606114230060152050401002004010020111214200611403&lt;br /&gt;     +006014026061144300611500504010020040100201042025210110030460140300&lt;br /&gt;     +611303046114030065024200401002004010044506100304601403006013030462&lt;br /&gt;     +140304650242004010020040100421012504044014230060140304541423046014&lt;br /&gt;     +032412100200401002004020647516250445162524244014230061144314122062&lt;br /&gt;     +010420247107230445162162006114220106244475151004110521447522212050&lt;br /&gt;     +611403046215020111214200611403006014026061144300601400504010020040&lt;br /&gt;     +100201042025210110030460140300611303046114030066024200401002004010&lt;br /&gt;     +044506100304601403006013030462140300610242004010020040100421012504&lt;br /&gt;     +044014230060140304541423046014033012100200401002004022243040142300&lt;br /&gt;     +601403005414231060140310121002004010020040210405242022006114030060&lt;br /&gt;     +142260611423006015405040100200401002011121420061140300601402606114&lt;br /&gt;     +430060146050401002004010020104202521011003046014030061130304611403&lt;br /&gt;     +006602420040100200401004450610030460140300601303046214030064024200&lt;br /&gt;     +401002004010042101250404401423006014030454142304601403301210020040&lt;br /&gt;     +100200402224304014230060140300541423106014032412100200401002004021&lt;br /&gt;     +040524202200611403006014226061142300601540504010020040100201112142&lt;br /&gt;     +006114030060140260611443006015405040100200401002010420252101100304&lt;br /&gt;     +601403006113030461140300660242004010020040100445061003046014030060&lt;br /&gt;     +130304621403006702420040100200401004210125040440142300601403045414&lt;br /&gt;     +230460140330121002004010020040222430401423006014030054142310601403&lt;br /&gt;     +401210020040100200402104052420220061140300601422606114230060156050&lt;br /&gt;     +401002004010020111214200611403006014026061144300601620504010020040&lt;br /&gt;     +100201042025210110030460140300611303046114030067024200401002004010&lt;br /&gt;     +044506100304601403006013030462140304600242004010020040100421012504&lt;br /&gt;     +044014230060140304541423046014033412100200401002004022243040142300&lt;br /&gt;     +601403005414231060142304121002004010020040210405242022006114030060&lt;br /&gt;     +142260611423006015605040100200401002011121420061140300601402606114&lt;br /&gt;     +430061144050401002004010020104202521011003046014030061130304611403&lt;br /&gt;     +006702420040100200401004450610030460140300601303046214030463024200&lt;br /&gt;     +401002004010042101250404401423006014030454142304601403341210020040&lt;br /&gt;     +100200402224304014230060140300541423106014232012100200401002004021&lt;br /&gt;     +040524202200611403006014226061142300601560504010020040100201112142&lt;br /&gt;     +006114030060140260611443006115205040100200401002010420252101100304&lt;br /&gt;     +601403006113030461140300670242004010020040100415172345211123452505&lt;br /&gt;     +100304601423106402441440206475162465210123452123024304611403006010&lt;br /&gt;     +042101250404401422606002430461140300611004210125040440142260610243&lt;br /&gt;     +046114030062100421012504044014226062024304611403006310042101250404&lt;br /&gt;     +401422606302430461140300641004210125040440142260640243046114030065&lt;br /&gt;     +100421012504044014226065024304611403006610042101250404401422606602&lt;br /&gt;     +430461140300671004210125040440142260670243046214030060100421012504&lt;br /&gt;     +044014426060140050611443006014220104202521011003105414030412142310&lt;br /&gt;     +601403104021040524202200621303006202430462140300631004210125040440&lt;br /&gt;     +144260601460506114430060150201042025210110031054140320121423106014&lt;br /&gt;     +032440210405242022006213030065024304621403006610042101250404401442&lt;br /&gt;     +606015405061144300601562010420252101100310541403341214231060140340&lt;br /&gt;     +402104052420220062130300700243046214030071100421012504044014426060&lt;br /&gt;     +162050611443006114020104202521011003105414230012142310601423044021&lt;br /&gt;     +040524202200621303046102430462140304621004210125040440144260611440&lt;br /&gt;     +506114430061146201042025210110031054142314121423106014232040210405&lt;br /&gt;     +242022006213030464024304621403046510042101250404401442606115205061&lt;br /&gt;     +146300611442010420252101100314541403046202434471162344711004210125&lt;br /&gt;     +0404401503006014030054&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-7569816598562213066?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/7569816598562213066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/03/here-is-resol-program-that-prints.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7569816598562213066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7569816598562213066'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/03/here-is-resol-program-that-prints.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-3766034022260143897</id><published>2010-03-22T00:00:00.000-07:00</published><updated>2010-03-22T00:00:01.930-07:00</updated><title type='text'></title><content type='html'>Here is 99 bottles of beer in &lt;a href="/2009/12/resol-programming-language.html"&gt;RESOL&lt;/a&gt;.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;C 99 BOTTLES IN RESOL&lt;br /&gt;001   DATA 000001&lt;br /&gt;      DATA 003,9876543210&lt;br /&gt;      DATA 004,9876543210&lt;br /&gt;      DATA 005,99&lt;br /&gt;      CALL 007,7&lt;br /&gt;      CALL 10002&lt;br /&gt;      CALL 002&lt;br /&gt;      STOP&lt;br /&gt;002   DATA 000001&lt;br /&gt;      DATA 002&lt;br /&gt;      DATA 002,10001&lt;br /&gt;      DATA 001,10001&lt;br /&gt;      DATA 10001&lt;br /&gt;      CONTINUE 002&lt;br /&gt;003   DATA 000001&lt;br /&gt;004   DATA 000001&lt;br /&gt;005   DATA 000002&lt;br /&gt;C DECREMENT COUNTER&lt;br /&gt;006   IF 003,0&lt;br /&gt;      DATA 003,9876543210&lt;br /&gt;      IF 003,0&lt;br /&gt;      DATA 004&lt;br /&gt;      DATA 003&lt;br /&gt;      DATA 005,004&lt;br /&gt;      DATA 005,003&lt;br /&gt;      DATA 005&lt;br /&gt;      CONTINUE 006&lt;br /&gt;007   DATA 000001&lt;br /&gt;      CALL 100,005&lt;br /&gt;      CALL 008&lt;br /&gt;      CALL 10000,0200 0415 0406 0200 0402 0405 0405 0502&lt;br /&gt;     +           0200 0415 0414 0200 0504 0408 0405&lt;br /&gt;     +           0200 0507 0401 0412 0412 0212 0200&lt;br /&gt;      CALL 100,005&lt;br /&gt;      CALL 008&lt;br /&gt;      CALL 10000,0200 0415 0406 0200 0402 0405 0405 0502 0214 0010&lt;br /&gt;      CALL 002&lt;br /&gt;      IF 00,005&lt;br /&gt;      CONTINUE 007,009&lt;br /&gt;      CALL 10000,0504 0401 0411 0405 0200 0415 0414 0405&lt;br /&gt;     +           0200 0404 0415 0507 0414 0200 0401 0414 0404&lt;br /&gt;     +           0200 0500 0401 0503 0503 0200 0409 0504&lt;br /&gt;     +           0200 0401 0502 0415 0505 0414 0404 0212 0200&lt;br /&gt;      CALL 006&lt;br /&gt;      CALL 100,005&lt;br /&gt;      CALL 008&lt;br /&gt;      CALL 10000,0200 0415 0406 0200 0402 0405 0405 0502&lt;br /&gt;     +           0200 0415 0414 0200 0504 0408 0405&lt;br /&gt;     +           0200 0507 0401 0412 0412 0214 0010 0010&lt;br /&gt;      CALL 002&lt;br /&gt;      CONTINUE 007&lt;br /&gt;C BOTTLE(S)&lt;br /&gt;008   CALL 10000,0200 0402 0415 0504 0504 0412 0405&lt;br /&gt;      IF 01,005&lt;br /&gt;      CONTINUE 008&lt;br /&gt;      CALL 10000,0503&lt;br /&gt;      CONTINUE 008&lt;br /&gt;009   CALL 10000,0407 0415 0200 0504 0415 0200 0504 0408 0405&lt;br /&gt;     +           0200 0503 0504 0415 0502 0405 0200 0401 0414 0404&lt;br /&gt;     +           0200 0402 0505 0509 0200 0503 0415 0413 0405&lt;br /&gt;     +           0200 0413 0415 0502 0405 0212 0200 0309 0309&lt;br /&gt;     +           0200 0402 0415 0504 0504 0412 0405 0503&lt;br /&gt;     +           0200 0415 0406 0200 0402 0405 0405 0502&lt;br /&gt;     +           0200 0415 0414 0200 0504 0408 0405&lt;br /&gt;     +           0200 0507 0401 0412 0412 0214 0010&lt;br /&gt;      DATA 007&lt;br /&gt;      CONTINUE 007&lt;br /&gt;C OUTPUT PASSED IN COUNT OR "NO MORE" WHEN COUNT IS 00&lt;br /&gt;100   DATA 000001&lt;br /&gt;      IF 100,0&lt;br /&gt;      CALL 101&lt;br /&gt;      CONTINUE 100,103&lt;br /&gt;101   DATA 100&lt;br /&gt;      IF 100,0&lt;br /&gt;      CALL 10000,0414041502000413041505020405&lt;br /&gt;      IF 100,0&lt;br /&gt;      CONTINUE 100,102&lt;br /&gt;      CALL 104&lt;br /&gt;102   DATA 100&lt;br /&gt;      CONTINUE 101&lt;br /&gt;103   CALL 104&lt;br /&gt;      DATA 100&lt;br /&gt;      CALL 104&lt;br /&gt;      DATA 100&lt;br /&gt;      CONTINUE 100&lt;br /&gt;104   IF 100,0&lt;br /&gt;      CALL 10000,0300&lt;br /&gt;      IF 100,1&lt;br /&gt;      CALL 10000,0301&lt;br /&gt;      IF 100,2&lt;br /&gt;      CALL 10000,0302&lt;br /&gt;      IF 100,3&lt;br /&gt;      CALL 10000,0303&lt;br /&gt;      IF 100,4&lt;br /&gt;      CALL 10000,0304&lt;br /&gt;      IF 100,5&lt;br /&gt;      CALL 10000,0305&lt;br /&gt;      IF 100,6&lt;br /&gt;      CALL 10000,0306&lt;br /&gt;      IF 100,7&lt;br /&gt;      CALL 10000,0307&lt;br /&gt;      IF 100,8&lt;br /&gt;      CALL 10000,0308&lt;br /&gt;      IF 100,9&lt;br /&gt;      CALL 10000,0309&lt;br /&gt;      CONTINUE 104&lt;br /&gt;C THIS IS A LIBRARY THAT CONVERTS 4-BIT ITEMS ENQUEUED INTO 10000 AS 2 DIGITS&lt;br /&gt;C INTO 3-BIT ITEMS IN 1 DIGIT THAT ARE AVAILABLE AT 10001.&lt;br /&gt;C CALL 10000 TO PROCESS ITEMS FROM 10000 INTO 10001.&lt;br /&gt;C CALL 10002 TO FLUSH THE FINAL DANGLING BITS (0-2 BITS).&lt;br /&gt;C&lt;br /&gt;C IF 000002 IS A DATA STATEMENT, CALLING 10000 WILL DEQUEUE FROM IT.  BEST&lt;br /&gt;C NOT TO HAVE 000002 AS A LABEL (WHICH WOULD REQUIRE A CONTINUATION LINE).&lt;br /&gt;C&lt;br /&gt;10000 DATA 000002&lt;br /&gt;      IF 10003,11000&lt;br /&gt;      CALL 10100&lt;br /&gt;      IF 10003,11001&lt;br /&gt;      CALL 10110&lt;br /&gt;      IF 10003,11002&lt;br /&gt;      CALL 10120&lt;br /&gt;      DATA 10003&lt;br /&gt;      DATA 10000&lt;br /&gt;      CONTINUE 10000&lt;br /&gt;10001 DATA 1&lt;br /&gt;C&lt;br /&gt;C FLUSH THE FINAL DANGLING BITS&lt;br /&gt;10002 IF 10003,11000&lt;br /&gt;      CONTINUE 10002&lt;br /&gt;      DATA 10001,10004&lt;br /&gt;      DATA 10004&lt;br /&gt;C REINITIALIZE 10003 TO 012&lt;br /&gt;      IF 10003,11001&lt;br /&gt;      DATA 10003&lt;br /&gt;      DATA 10003&lt;br /&gt;      DATA 10003,012&lt;br /&gt;      CONTINUE 10002&lt;br /&gt;C&lt;br /&gt;C 10003 HOLDS THE NUMBER OF DANGLING BITS&lt;br /&gt;10003 DATA 1,012&lt;br /&gt;C 10004 HOLDS THE VALUE OF THE DANGLING BITS&lt;br /&gt;10004 DATA 1&lt;br /&gt;C&lt;br /&gt;C NO DANGLING BITS FROM BEFORE.  LEAVES 1 DANGLING BIT FOR NEXT ITEM.&lt;br /&gt;10100 IF 10000,12000&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12000&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      CONTINUE 10100&lt;br /&gt;C&lt;br /&gt;C 1 DANGLING BIT FROM BEFORE.  LEAVES 2 DANGLING BITS FOR NEXT ITEM.&lt;br /&gt;10110 IF 10004,11000&lt;br /&gt;      CALL 10111&lt;br /&gt;      IF 10004,11004&lt;br /&gt;      CALL 10112&lt;br /&gt;      DATA 10004&lt;br /&gt;      CONTINUE 10110&lt;br /&gt;C DANGLING 0 FROM BEFORE&lt;br /&gt;10111 IF 10000,12000&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12000&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      CONTINUE 10111&lt;br /&gt;C DANGLING 1 FROM BEFORE&lt;br /&gt;10112 IF 10000,12000&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12000&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10004,11000&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10004,11002&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10004,11004&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10004,11006&lt;br /&gt;      CONTINUE 10112&lt;br /&gt;C&lt;br /&gt;C 2 DANGLING BITS FROM BEFORE.  LEAVES NO DANGLING BITS FOR NEXT ITEM.&lt;br /&gt;10120 IF 10004,11000&lt;br /&gt;      CALL 10121&lt;br /&gt;      IF 10004,11002&lt;br /&gt;      CALL 10122&lt;br /&gt;      IF 10004,11004&lt;br /&gt;      CALL 10123&lt;br /&gt;      IF 10004,11006&lt;br /&gt;      CALL 10124&lt;br /&gt;      DATA 10003,13012&lt;br /&gt;      DATA 10004&lt;br /&gt;      IF 10000,12000&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      CONTINUE 10120&lt;br /&gt;C DANGLING 00 FROM BEFORE&lt;br /&gt;10121 IF 10000,12000&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11000&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11001&lt;br /&gt;      CONTINUE 10121&lt;br /&gt;C DANGLING 01 FROM BEFORE&lt;br /&gt;10122 IF 10000,12000&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11002&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11003&lt;br /&gt;      CONTINUE 10122&lt;br /&gt;C DANGLING 10 FROM BEFORE&lt;br /&gt;10123 IF 10000,12000&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11004&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11005&lt;br /&gt;      CONTINUE 10123&lt;br /&gt;C DANGLING 11 FROM BEFORE&lt;br /&gt;10124 IF 10000,12000&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12001&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12002&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12003&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12004&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12005&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12006&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12007&lt;br /&gt;      DATA 10001,11006&lt;br /&gt;      IF 10000,12008&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12009&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12010&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12011&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12012&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12013&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12014&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      IF 10000,12015&lt;br /&gt;      DATA 10001,11007&lt;br /&gt;      CONTINUE 10124&lt;br /&gt;C&lt;br /&gt;C CONSTANTS&lt;br /&gt;11000 DATA 1,0&lt;br /&gt;11001 DATA 1,1&lt;br /&gt;11002 DATA 1,2&lt;br /&gt;11003 DATA 1,3&lt;br /&gt;11004 DATA 1,4&lt;br /&gt;11005 DATA 1,5&lt;br /&gt;11006 DATA 1,6&lt;br /&gt;11007 DATA 1,7&lt;br /&gt;12000 DATA 2,00&lt;br /&gt;12001 DATA 2,01&lt;br /&gt;12002 DATA 2,02&lt;br /&gt;12003 DATA 2,03&lt;br /&gt;12004 DATA 2,04&lt;br /&gt;12005 DATA 2,05&lt;br /&gt;12006 DATA 2,06&lt;br /&gt;12007 DATA 2,07&lt;br /&gt;12008 DATA 2,08&lt;br /&gt;12009 DATA 2,09&lt;br /&gt;12010 DATA 2,10&lt;br /&gt;12011 DATA 2,11&lt;br /&gt;12012 DATA 2,12&lt;br /&gt;12013 DATA 2,13&lt;br /&gt;12014 DATA 2,14&lt;br /&gt;12015 DATA 2,15&lt;br /&gt;13012 DATA 3,012&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-3766034022260143897?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/3766034022260143897/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/03/here-is-99-bottles-of-beer-in-resol.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3766034022260143897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3766034022260143897'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/03/here-is-99-bottles-of-beer-in-resol.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-891490758020868236</id><published>2010-03-15T00:00:00.000-07:00</published><updated>2010-03-15T00:00:07.721-07:00</updated><title type='text'></title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class ToBytes a where&lt;br /&gt;    toBytes :: a -&gt; [Word8]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then, since many objects, when converted to a list of bytes, are just the concatenation of the conversion of component objects, I defined&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;concatAccessors :: [a -&gt; [b]] -&gt; a -&gt; [b]&lt;br /&gt;concatAccessors = flip (.) (flip ($)) . flip concatMap&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;instance ToBytes JVMClass where&lt;br /&gt;    toBytes = concatAccessors [&lt;br /&gt;        toBytes . jvmClassMagic,&lt;br /&gt;        toBytes . jvmClassMinorVersion,&lt;br /&gt;        toBytes . jvmClassMajorVersion,&lt;br /&gt;        toBytes . jvmClassConstantPool,&lt;br /&gt;        toBytes . jvmClassAccessFlags,&lt;br /&gt;        toBytes . jvmClassThisClass,&lt;br /&gt;        toBytes . jvmClassSuperClass,&lt;br /&gt;        toBytes . jvmClassInterfaces,&lt;br /&gt;        toBytes . jvmClassFields,&lt;br /&gt;        toBytes . jvmClassMethods,&lt;br /&gt;        toBytes . jvmClassAttributes&lt;br /&gt;        ]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;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&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;instance ToBytes a =&gt; ToBytes [a] where&lt;br /&gt;    toBytes l = toBytes (fromIntegral (length l) :: Word16) ++ concatMap toBytes l&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;For reading class files, I learned how to make a state-transformer monad, which looks like this&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;newtype ST st a = ST (st -&gt; (a,st))&lt;br /&gt;&lt;br /&gt;instance Monad (ST st) where&lt;br /&gt;    p &gt;&gt;= q = ST (uncurry (s . q) . s p)    where s (ST t) = t&lt;br /&gt;    return = ST . (,)&lt;br /&gt;&lt;br /&gt;runST :: ST st a -&gt; st -&gt; a&lt;br /&gt;runST (ST t) = fst . t&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;readJVMClass :: ST State JVMClass&lt;br /&gt;readJVMClass = do&lt;br /&gt;    magic &lt;- readWord32&lt;br /&gt;    minorVersion &lt;- readWord16&lt;br /&gt;    majorVersion &lt;- readWord16&lt;br /&gt;    constantPool &lt;- readConstantPool&lt;br /&gt;    accessFlags &lt;- readWord16&lt;br /&gt;    thisClass &lt;- readWord16&lt;br /&gt;    superClass &lt;- readWord16&lt;br /&gt;    interfaces &lt;- readList readWord16&lt;br /&gt;    fields &lt;- readList readField&lt;br /&gt;    methods &lt;- readList readMethod&lt;br /&gt;    attributes &lt;- readList readAttribute&lt;br /&gt;    return (JVMClass magic minorVersion majorVersion constantPool accessFlags&lt;br /&gt;                     thisClass superClass interfaces fields methods attributes)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which is very maintainable.&lt;br /&gt;&lt;br /&gt;Using Functor and Applicative&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;instance Functor (ST st) where&lt;br /&gt;    fmap f p = do { a &lt;- p; return (f a) }&lt;br /&gt;&lt;br /&gt;instance Applicative (ST st) where&lt;br /&gt;    pure = return&lt;br /&gt;    p &lt;*&gt; q = do { f &lt;- p; a &lt;- q; return (f a) }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;it could be written more concisely, but with more weird operators:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;readJVMClass = JVMClass &lt;$&gt; readWord32&lt;br /&gt;                        &lt;*&gt; readWord16&lt;br /&gt;                        &lt;*&gt; readWord16&lt;br /&gt;                        &lt;*&gt; readConstantPool&lt;br /&gt;                        &lt;*&gt; readWord16&lt;br /&gt;                        &lt;*&gt; readWord16&lt;br /&gt;                        &lt;*&gt; readWord16&lt;br /&gt;                        &lt;*&gt; readList readWord16&lt;br /&gt;                        &lt;*&gt; readList readField&lt;br /&gt;                        &lt;*&gt; readList readMethod&lt;br /&gt;                        &lt;*&gt; readList readAttribute&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-891490758020868236?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/891490758020868236/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/03/after-getting-reacquainted-with-haskell.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/891490758020868236'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/891490758020868236'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/03/after-getting-reacquainted-with-haskell.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-4791760459672918794</id><published>2010-03-08T00:00:00.000-08:00</published><updated>2010-03-08T00:00:10.813-08:00</updated><title type='text'></title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-4791760459672918794?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/4791760459672918794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/03/there-was-some-feature-that-due-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/4791760459672918794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/4791760459672918794'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/03/there-was-some-feature-that-due-to.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-2144118024813674593</id><published>2010-03-01T00:00:00.000-08:00</published><updated>2010-03-01T00:00:12.485-08:00</updated><title type='text'></title><content type='html'>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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-2144118024813674593?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/2144118024813674593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/03/i-got-3am-call-because-of-some-problem.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2144118024813674593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2144118024813674593'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/03/i-got-3am-call-because-of-some-problem.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-3493864349175854772</id><published>2010-02-22T00:00:00.001-08:00</published><updated>2010-02-22T00:00:04.874-08:00</updated><title type='text'></title><content type='html'>Here is an interpreter for &lt;a href="/2009/06/01-programming-language.html"&gt;01_&lt;/a&gt; that I wrote in 01_.  It compiles the 01_ source code into a bit code, and then interprets that bit code.&lt;br /&gt;&lt;br /&gt;One limitation is that the top-level function evaluated is the first function defined in the source, instead of the function specified on the command line or inferred from the filename.  This could easily be coded to be, in a fashion, specified from the command line.  This would be somewhat awkward, since the 01_ code does not get the actual command line data, but rather, the contents of the file named in the command line, so the name of the function to be evaluated would have to be put into a file or piped into stdin to be received by the interpreter.&lt;br /&gt;&lt;br /&gt;Another limitation is that it can only pass in a maximum of 9 arguments to the top level function.  (Any additional arguments will be given nil.)  This limit can be easily changed by changing the arglist function (and the interp and bitcode functions) to take a different number of arguments.&lt;br /&gt;&lt;h5&gt;Bit code format&lt;/h5&gt;&lt;br /&gt;Here is the bit code format used by my 01_ interpreter.&lt;br /&gt;&lt;br /&gt;Parenthesis indicates a list.  Ellipses indicates zero or more of the&lt;br /&gt;preceding item.  A vertical bar indicates alternatives.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;program = (name ones names functions)&lt;br /&gt;names = (name name ...)&lt;br /&gt;functions = (definitions definitions ...)&lt;br /&gt;definitions = (definition definition ...)&lt;br /&gt;definition = (patterns body)&lt;br /&gt;patterns = (pattern ...)&lt;br /&gt;pattern = bound-pattern | literal-pattern | wild-pattern&lt;br /&gt;bound-pattern = 0 bits&lt;br /&gt;literal-pattern = 1 0 bits&lt;br /&gt;wild-pattern = 1 1 bits&lt;br /&gt;bits = bit ...&lt;br /&gt;bit = 0 | 1&lt;br /&gt;ones = 1 ...&lt;br /&gt;body = op op ...&lt;br /&gt;op = push | concat&lt;br /&gt;push = 0 value&lt;br /&gt;concat = 1 value&lt;br /&gt;value = literal | binding | funcall&lt;br /&gt;binding = 0 ones&lt;br /&gt;literal = 1 0 bits&lt;br /&gt;funcall = 1 1 (bits ones)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The program has the name of the function to apply, the number of arguments that function takes, a pair of lists forming an association list of names to functions.&lt;br /&gt;&lt;br /&gt;A push op pushes its value onto the local stack to be used as an argument to a function call.  A concat op concatenates its result to the value that is returned by the current function.&lt;br /&gt;&lt;br /&gt;A binding value has an index to the bound parameters of the function.  Let n = the number of bound parameters, then 0 is the last parameter, and n - 1 is the first parameter.&lt;br /&gt;&lt;br /&gt;A funcall value has the name of the function and the number of arguments that function takes.&lt;br /&gt;&lt;br /&gt;All the counts, the binding index and the number of arguments taken by a function, are in base 1.&lt;br /&gt;&lt;h5&gt;Library functions&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;== library&lt;br /&gt;&lt;br /&gt;== force a pattern match failure&lt;br /&gt;error 0 = error _.&lt;br /&gt;&lt;br /&gt;concat a b = a b.&lt;br /&gt;&lt;br /&gt;== lists&lt;br /&gt;&lt;br /&gt;== first item in the list&lt;br /&gt;head 0. = _.&lt;br /&gt;head 11rest = 1 head rest.&lt;br /&gt;head 10rest = 0 head rest.&lt;br /&gt;head _ = _.&lt;br /&gt;&lt;br /&gt;== the list with the first item removed&lt;br /&gt;tail 0rest = rest.&lt;br /&gt;tail 11rest = tail rest.&lt;br /&gt;tail 10rest = tail rest.&lt;br /&gt;tail _ = _.&lt;br /&gt;&lt;br /&gt;list-encode _ = 0.&lt;br /&gt;list-encode 1x = 11 list-encode x.&lt;br /&gt;list-encode 0x = 10 list-encode x.&lt;br /&gt;&lt;br /&gt;== association lists&lt;br /&gt;&lt;br /&gt;== association list lookup&lt;br /&gt;alist-lookup key klist dlist =&lt;br /&gt;    if-equal key head klist&lt;br /&gt;             head dlist&lt;br /&gt;             alist-lookup key tail klist tail dlist.&lt;br /&gt;alist-lookup . _ . = _.&lt;br /&gt;&lt;br /&gt;== association list update&lt;br /&gt;alist-update key data klist dlist =&lt;br /&gt;    if-equal key head klist&lt;br /&gt;             concat list-encode data&lt;br /&gt;                    tail dlist&lt;br /&gt;             concat list-encode head dlist&lt;br /&gt;                    alist-update key data&lt;br /&gt;                                 tail klist&lt;br /&gt;                                 tail dlist.&lt;br /&gt;&lt;br /&gt;alist-append key data klist dlist =&lt;br /&gt;    if-equal key head klist&lt;br /&gt;             concat list-encode concat head dlist&lt;br /&gt;                                       list-encode data&lt;br /&gt;                    tail dlist&lt;br /&gt;             concat list-encode head dlist&lt;br /&gt;                    alist-append key data&lt;br /&gt;                                 tail klist&lt;br /&gt;                                 tail dlist.&lt;br /&gt;&lt;br /&gt;== stacks&lt;br /&gt;&lt;br /&gt;== new empty stack&lt;br /&gt;empty-stack = 0_.&lt;br /&gt;&lt;br /&gt;== number of items in the stack (in base 1)&lt;br /&gt;stack-count 0stack = _.&lt;br /&gt;stack-count 1stack = 1 stack-count stack.&lt;br /&gt;&lt;br /&gt;drop-stack-count 0stack = stack.&lt;br /&gt;drop-stack-count 1stack = drop-stack-count stack.&lt;br /&gt;&lt;br /&gt;== top of the stack&lt;br /&gt;top 0. = _. == stack underflow&lt;br /&gt;top stack = top' decrement-count stack-count stack drop-stack-count stack.&lt;br /&gt;&lt;br /&gt;top' count 0stack-data = _.&lt;br /&gt;top' count 10stack-data = 0 top' count drop-stack-bit count stack-data.&lt;br /&gt;top' count 11stack-data = 1 top' count drop-stack-bit count stack-data.&lt;br /&gt;&lt;br /&gt;decrement-count 1count = count.&lt;br /&gt;&lt;br /&gt;drop-stack-bit _ stack-data = stack-data.&lt;br /&gt;drop-stack-bit 1count  0stack-data = drop-stack-bit count stack-data.&lt;br /&gt;drop-stack-bit 1count 10stack-data = drop-stack-bit count stack-data.&lt;br /&gt;drop-stack-bit 1count 11stack-data = drop-stack-bit count stack-data.&lt;br /&gt;&lt;br /&gt;== returns stack with data pushed on top&lt;br /&gt;push data stack =&lt;br /&gt;    1 stack-count stack 0 push' data stack-count stack drop-stack-count stack.&lt;br /&gt;&lt;br /&gt;push' _ count stack-data =&lt;br /&gt;    0 take-stack-bit count stack-data&lt;br /&gt;    push' _ count drop-stack-bit count stack-data.&lt;br /&gt;push' 0data count stack-data =&lt;br /&gt;    10 take-stack-bit count stack-data&lt;br /&gt;    push' data count drop-stack-bit count stack-data.&lt;br /&gt;push' 1data count stack-data =&lt;br /&gt;    11 take-stack-bit count stack-data&lt;br /&gt;    push' data count drop-stack-bit count stack-data.&lt;br /&gt;&lt;br /&gt;take-stack-bit _ . = _.&lt;br /&gt;take-stack-bit 1count  0stack-data =  0 take-stack-bit count stack-data.&lt;br /&gt;take-stack-bit 1count 10stack-data = 10 take-stack-bit count stack-data.&lt;br /&gt;take-stack-bit 1count 11stack-data = 11 take-stack-bit count stack-data.&lt;br /&gt;&lt;br /&gt;== returns stack with the top item popped&lt;br /&gt;pop 0. = 0_. == stack underflow&lt;br /&gt;pop 10. = 0_. == 1 item optimization&lt;br /&gt;pop 1stack = stack-count stack 0 pop' stack-count stack drop-stack-count stack.&lt;br /&gt;&lt;br /&gt;pop' count 0stack-data =&lt;br /&gt;    take-stack-bit count stack-data&lt;br /&gt;    pop' count drop-stack-bit count stack-data.&lt;br /&gt;pop' count 10stack-data =&lt;br /&gt;    take-stack-bit count stack-data&lt;br /&gt;    pop' count drop-stack-bit count stack-data.&lt;br /&gt;pop' count 11stack-data =&lt;br /&gt;    take-stack-bit count stack-data&lt;br /&gt;    pop' count drop-stack-bit count stack-data.&lt;br /&gt;&lt;br /&gt;== conditional&lt;br /&gt;if-equal 0x 0y true false = if-equal x y true false.&lt;br /&gt;if-equal 1x 1y true false = if-equal x y true false.&lt;br /&gt;if-equal _ _ true . = true.&lt;br /&gt;if-equal . . . false = false.&lt;br /&gt;&lt;br /&gt;==&lt;br /&gt;take-bits _ . = _.&lt;br /&gt;take-bits . _ = _.&lt;br /&gt;take-bits 0bits 0data = 0 take-bits bits data.&lt;br /&gt;take-bits 1bits 0data = 0 take-bits bits data.&lt;br /&gt;take-bits 0bits 1data = 1 take-bits bits data.&lt;br /&gt;take-bits 1bits 1data = 1 take-bits bits data.&lt;br /&gt;&lt;br /&gt;drop-bits _ data = data.&lt;br /&gt;drop-bits . _ = _.&lt;br /&gt;drop-bits 0bits 0data = drop-bits bits data.&lt;br /&gt;drop-bits 1bits 0data = drop-bits bits data.&lt;br /&gt;drop-bits 0bits 1data = drop-bits bits data.&lt;br /&gt;drop-bits 1bits 1data = drop-bits bits data.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;Tokenizer&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;== 01_ tokenizer&lt;br /&gt;== token tokenized&lt;br /&gt;== 0     0&lt;br /&gt;== 1     1&lt;br /&gt;== _     00&lt;br /&gt;== .     01&lt;br /&gt;== =     10&lt;br /&gt;&lt;br /&gt;== input stream to list of tokens&lt;br /&gt;tokenize in = tokenize' in _.&lt;br /&gt;&lt;br /&gt;tokenize' _ . = _.&lt;br /&gt;&lt;br /&gt;== comment&lt;br /&gt;tokenize' 00111101 00111101in flag = end-symbol flag&lt;br /&gt;                                    drop-comment in.&lt;br /&gt;&lt;br /&gt;== 0&lt;br /&gt;tokenize' 00110000in flag = end-symbol flag&lt;br /&gt;                            100 tokenize' in _.&lt;br /&gt;&lt;br /&gt;== 1&lt;br /&gt;tokenize' 00110001in flag = end-symbol flag&lt;br /&gt;                            110 tokenize' in _.&lt;br /&gt;&lt;br /&gt;== _&lt;br /&gt;tokenize' 01011111in flag = end-symbol flag&lt;br /&gt;                            10100 tokenize' in _.&lt;br /&gt;&lt;br /&gt;== .&lt;br /&gt;tokenize' 00101110in flag = end-symbol flag&lt;br /&gt;                            10110 tokenize' in _.&lt;br /&gt;&lt;br /&gt;== =&lt;br /&gt;tokenize' 00111101in flag = end-symbol flag&lt;br /&gt;                            11100 tokenize' in _.&lt;br /&gt;&lt;br /&gt;== whitespace&lt;br /&gt;tokenize' 00100000in flag = end-symbol flag tokenize' in _. == SPC&lt;br /&gt;tokenize' 00001001in flag = end-symbol flag tokenize' in _. == TAB&lt;br /&gt;tokenize' 00001010in flag = end-symbol flag tokenize' in _. == LF&lt;br /&gt;tokenize' 00001101in flag = end-symbol flag tokenize' in _. == CR&lt;br /&gt;&lt;br /&gt;== symbol&lt;br /&gt;tokenize' in . = take-symbol 00000000 in.&lt;br /&gt;&lt;br /&gt;end-symbol _ = _.&lt;br /&gt;end-symbol . = 0.&lt;br /&gt;&lt;br /&gt;take-symbol _ in = tokenize' in 0.&lt;br /&gt;take-symbol 0bits 0in = 10 take-symbol bits in.&lt;br /&gt;take-symbol 0bits 1in = 11 take-symbol bits in.&lt;br /&gt;&lt;br /&gt;== comment&lt;br /&gt;drop-comment _ = _.&lt;br /&gt;drop-comment 00001010in = tokenize' in _.&lt;br /&gt;drop-comment in = drop-comment drop-bits 00000000 in.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;==&lt;br /&gt;test-tokenize in = test-tokenize-out tokenize in _.&lt;br /&gt;&lt;br /&gt;test-tokenize-out _ . = _.&lt;br /&gt;test-tokenize-out list flag = test-tokenize-out-one head list tail list flag.&lt;br /&gt;&lt;br /&gt;test-tokenize-out-one 0_  list . = 00110000 test-tokenize-out list _.&lt;br /&gt;test-tokenize-out-one 1_  list . = 00110001 test-tokenize-out list _.&lt;br /&gt;test-tokenize-out-one 00_ list . = 01011111 test-tokenize-out list _.&lt;br /&gt;test-tokenize-out-one 01_ list . = 00101110 test-tokenize-out list _.&lt;br /&gt;test-tokenize-out-one 10_ list . = 00111101 test-tokenize-out list _.&lt;br /&gt;&lt;br /&gt;test-tokenize-out-one one list flag = test-tokenize-out-sep flag one test-tokenize-out list 0.&lt;br /&gt;&lt;br /&gt;test-tokenize-out-sep _ = _.&lt;br /&gt;test-tokenize-out-sep . = 00100000.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;Parser&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;== parse a list of 01_ tokens into a list of function names&lt;br /&gt;&lt;br /&gt;parse-names tokens = parse-names' head tokens tail tokens _.&lt;br /&gt;&lt;br /&gt;parse-names' _ . list = list.&lt;br /&gt;parse-names' 0_  . . = error _. == expecting symbol&lt;br /&gt;parse-names' 1_  . . = error _. == expecting symbol&lt;br /&gt;parse-names' 00_ . . = error _. == expecting symbol&lt;br /&gt;parse-names' 01_ . . = error _. == expecting symbol&lt;br /&gt;parse-names' 10_ . . = error _. == expecting symbol&lt;br /&gt;parse-names' name tokens list =&lt;br /&gt;    parse-names' head parse-drop-def head tokens tail tokens&lt;br /&gt;                 tail parse-drop-def head tokens tail tokens&lt;br /&gt;                 add-unique name list.&lt;br /&gt;&lt;br /&gt;add-unique item _ = list-encode item.&lt;br /&gt;add-unique item list = list-encode head list&lt;br /&gt;                       if-equal item head list&lt;br /&gt;                                tail list&lt;br /&gt;                                add-unique item&lt;br /&gt;                                           tail list.&lt;br /&gt;&lt;br /&gt;parse-drop-def 10_ tokens = parse-drop-def-body head tokens tail tokens.&lt;br /&gt;parse-drop-def . tokens = parse-drop-def head tokens tail tokens.&lt;br /&gt;&lt;br /&gt;parse-drop-def-body 01_ tokens = tokens.&lt;br /&gt;parse-drop-def-body . tokens = parse-drop-def-body head tokens tail tokens.&lt;br /&gt;&lt;br /&gt;test-parse-names in = test-tokenize-out parse-names tokenize in _.&lt;br /&gt;&lt;br /&gt;== given a list of items, return a list of empty lists of equal length&lt;br /&gt;== this can be used to initialize association lists&lt;br /&gt;== keys cannot be nil&lt;br /&gt;alist-empty-values keys = alist-empty-values' head keys tail keys.&lt;br /&gt;&lt;br /&gt;alist-empty-values' _ . = _.&lt;br /&gt;alist-empty-values' . keys = 0 alist-empty-values' head keys tail keys.&lt;br /&gt;&lt;br /&gt;== collect arities from list of 01_ tokens&lt;br /&gt;parse-arities names tokens = parse-arities' names&lt;br /&gt;                                            alist-empty-values names&lt;br /&gt;                                            head tokens&lt;br /&gt;                                            tail tokens.&lt;br /&gt;&lt;br /&gt;parse-arities' names arities _ . = arities.&lt;br /&gt;parse-arities' names arities name tokens =&lt;br /&gt;    parse-arities-count-args names arities name _&lt;br /&gt;                             head tokens&lt;br /&gt;                             tail tokens&lt;br /&gt;                             _.&lt;br /&gt;&lt;br /&gt;parse-arities-count-args names arities name count _ tokens flag = error _.&lt;br /&gt;                == unexpected EOF&lt;br /&gt;&lt;br /&gt;parse-arities-count-args names arities name count 10_ tokens _ =&lt;br /&gt;    == got = without any bits&lt;br /&gt;    parse-arities' names&lt;br /&gt;                   alist-update name count names arities&lt;br /&gt;                   head parse-drop-def-body head tokens tail tokens&lt;br /&gt;                   tail parse-drop-def-body head tokens tail tokens.&lt;br /&gt;&lt;br /&gt;parse-arities-count-args names arities name count 10_ tokens . =&lt;br /&gt;    == got = with leading bits&lt;br /&gt;    parse-arities' names&lt;br /&gt;                   alist-update name&lt;br /&gt;                                concat 1 count&lt;br /&gt;                                names arities&lt;br /&gt;                   head parse-drop-def-body head tokens tail tokens&lt;br /&gt;                   tail parse-drop-def-body head tokens tail tokens.&lt;br /&gt;&lt;br /&gt;parse-arities-count-args names arities name count 0_ tokens . =&lt;br /&gt;    parse-arities-count-args names arities name count&lt;br /&gt;                             head tokens&lt;br /&gt;                             tail tokens&lt;br /&gt;                             0.&lt;br /&gt;&lt;br /&gt;parse-arities-count-args names arities name count 1_ tokens . =&lt;br /&gt;    parse-arities-count-args names arities name count&lt;br /&gt;                             head tokens&lt;br /&gt;                             tail tokens&lt;br /&gt;                             0.&lt;br /&gt;&lt;br /&gt;parse-arities-count-args names arities name count . tokens . =&lt;br /&gt;    parse-arities-count-args names arities name&lt;br /&gt;                             concat 1 count&lt;br /&gt;                             head tokens&lt;br /&gt;                             tail tokens&lt;br /&gt;                             _.&lt;br /&gt;&lt;br /&gt;test-parse-arities in = test-parse-arities' parse-names tokenize in&lt;br /&gt;                                            tokenize in.&lt;br /&gt;test-parse-arities' names tokens =&lt;br /&gt;    test-alist-out names parse-arities names tokens.&lt;br /&gt;&lt;br /&gt;test-alist-out _ . = _.&lt;br /&gt;test-alist-out klist dlist =&lt;br /&gt;    head klist&lt;br /&gt;    00111101&lt;br /&gt;    test-bits-out head dlist&lt;br /&gt;    00001010&lt;br /&gt;    test-alist-out tail klist tail dlist.&lt;br /&gt;&lt;br /&gt;test-bits-out _ = _.&lt;br /&gt;test-bits-out 0b = 00110000 test-bits-out b.&lt;br /&gt;test-bits-out 1b = 00110001 test-bits-out b.&lt;br /&gt;&lt;br /&gt;== parse&lt;br /&gt;parse tokens = parse' parse-names tokens tokens.&lt;br /&gt;parse' names tokens = parse'' names parse-arities names tokens tokens.&lt;br /&gt;parse'' names arities tokens =&lt;br /&gt;    list-encode head names&lt;br /&gt;    list-encode head arities&lt;br /&gt;    list-encode names&lt;br /&gt;    list-encode parse-functions names arities&lt;br /&gt;                                alist-empty-values names&lt;br /&gt;                                tokens.&lt;br /&gt;&lt;br /&gt;parse-functions names arities functions _ = functions.&lt;br /&gt;&lt;br /&gt;parse-functions names arities functions tokens =&lt;br /&gt;    parse-functions names arities&lt;br /&gt;                    alist-append head tokens&lt;br /&gt;                                 parse-def-args names arities _ _ _&lt;br /&gt;                                                head tail tokens&lt;br /&gt;                                                tail tail tokens&lt;br /&gt;                                 names&lt;br /&gt;                                 functions&lt;br /&gt;                    parse-drop-def head tokens tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-args names arities bindings bits patterns 10_ tokens = == =&lt;br /&gt;    if-equal bits _&lt;br /&gt;             list-encode patterns&lt;br /&gt;             list-encode concat patterns&lt;br /&gt;                                list-encode concat 10 bits == literal pattern&lt;br /&gt;    parse-def-body names arities bindings _ _ _ head tokens tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-args names arities bindings bits patterns 0_ tokens = == 0&lt;br /&gt;    parse-def-args names arities bindings&lt;br /&gt;                   concat bits 0&lt;br /&gt;                   patterns&lt;br /&gt;                   head tokens&lt;br /&gt;                   tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-args names arities bindings bits patterns 1_ tokens = == 1&lt;br /&gt;    parse-def-args names arities bindings&lt;br /&gt;                   concat bits 1&lt;br /&gt;                   patterns&lt;br /&gt;                   head tokens&lt;br /&gt;                   tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-args names arities bindings bits patterns 00_ tokens = == _&lt;br /&gt;    == literal pattern&lt;br /&gt;    parse-def-args names arities bindings&lt;br /&gt;                   _&lt;br /&gt;                   concat patterns&lt;br /&gt;                          list-encode concat 10 bits&lt;br /&gt;                   head tokens&lt;br /&gt;                   tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-args names arities bindings bits patterns 01_ tokens = == .&lt;br /&gt;    == wild pattern&lt;br /&gt;    parse-def-args names arities bindings&lt;br /&gt;                   _&lt;br /&gt;                   concat patterns&lt;br /&gt;                          list-encode concat 11 bits&lt;br /&gt;                   head tokens&lt;br /&gt;                   tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-args names arities bindings bits patterns arg tokens =&lt;br /&gt;    == bound pattern&lt;br /&gt;    parse-def-args names arities&lt;br /&gt;                   concat list-encode arg&lt;br /&gt;                          bindings&lt;br /&gt;                   _&lt;br /&gt;                   concat patterns&lt;br /&gt;                          list-encode concat 0 bits&lt;br /&gt;                   head tokens&lt;br /&gt;                   tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-body names arities bindings argcounts funcalls bits _ . = error _.&lt;br /&gt;&lt;br /&gt;parse-def-body names arities bindings argcounts funcalls bits 0_ tokens =&lt;br /&gt;        parse-def-body names arities bindings&lt;br /&gt;                       argcounts funcalls&lt;br /&gt;                       concat bits 0&lt;br /&gt;                       head tokens&lt;br /&gt;                       tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-body names arities bindings argcounts funcalls bits 1_ tokens =&lt;br /&gt;        parse-def-body names arities bindings&lt;br /&gt;                       argcounts funcalls&lt;br /&gt;                       concat bits 1&lt;br /&gt;                       head tokens&lt;br /&gt;                       tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-body names arities bindings argcounts funcalls _ 01_ . = _.&lt;br /&gt;    == . end of definition&lt;br /&gt;&lt;br /&gt;parse-def-body names arities bindings argcounts funcalls _ 00_ tokens =&lt;br /&gt;    == _ nil constant&lt;br /&gt;    list-encode if-equal argcounts _&lt;br /&gt;                         110_ == concat nil&lt;br /&gt;                         010  == push nil&lt;br /&gt;    check-argcounts argcounts funcalls&lt;br /&gt;                    head argcounts&lt;br /&gt;    parse-def-body names arities bindings&lt;br /&gt;                   decrement-argcounts argcounts head argcounts&lt;br /&gt;                   decrement-funcalls argcounts funcalls head argcounts&lt;br /&gt;                   _&lt;br /&gt;                   head tokens&lt;br /&gt;                   tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-body names arities bindings argcounts funcalls _ token tokens =&lt;br /&gt;    == symbol: either binding or funcall&lt;br /&gt;    parse-def-try-binding names arities bindings argcounts funcalls tokens&lt;br /&gt;                          token bindings _&lt;br /&gt;                          alist-lookup token names arities.&lt;br /&gt;&lt;br /&gt;parse-def-body names arities bindings argcounts funcalls _ token tokens =&lt;br /&gt;    == symbol: either binding or funcall&lt;br /&gt;    parse-def-try-binding names arities bindings argcounts funcalls&lt;br /&gt;                          tokens&lt;br /&gt;                          token bindings _&lt;br /&gt;                          alist-lookup token names arities.&lt;br /&gt;&lt;br /&gt;parse-def-body names arities bindings argcounts funcalls bits 00_ tokens =&lt;br /&gt;    == _ terminated constant&lt;br /&gt;    list-encode if-equal argcounts _&lt;br /&gt;                         concat 110 bits == concat nil&lt;br /&gt;                         concat 010 bits == push nil&lt;br /&gt;    check-argcounts argcounts funcalls&lt;br /&gt;                    head argcounts&lt;br /&gt;    parse-def-body names arities bindings&lt;br /&gt;                   decrement-argcounts argcounts head argcounts&lt;br /&gt;                   decrement-funcalls argcounts funcalls head argcounts&lt;br /&gt;                   _&lt;br /&gt;                   head tokens&lt;br /&gt;                   tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-body names arities bindings argcounts funcalls bits token tokens =&lt;br /&gt;    == end of constant&lt;br /&gt;    list-encode if-equal argcounts _&lt;br /&gt;                         concat 110 bits == concat nil&lt;br /&gt;                         concat 010 bits == push nil&lt;br /&gt;    check-argcounts argcounts funcalls&lt;br /&gt;                    head argcounts&lt;br /&gt;    parse-def-body names arities bindings&lt;br /&gt;                   decrement-argcounts argcounts head argcounts&lt;br /&gt;                   decrement-funcalls argcounts funcalls head argcounts&lt;br /&gt;                   _&lt;br /&gt;                   token&lt;br /&gt;                   tokens.&lt;br /&gt;&lt;br /&gt;parse-def-try-binding names arities bindings argcounts funcalls tokens&lt;br /&gt;                      name _ . _ =&lt;br /&gt;    == not in bindings, nullary funcall&lt;br /&gt;    list-encode if-equal _ argcounts&lt;br /&gt;                         concat 111 concat list-encode name 0&lt;br /&gt;                         concat 011 concat list-encode name 0&lt;br /&gt;    check-argcounts argcounts funcalls&lt;br /&gt;                    head argcounts&lt;br /&gt;    parse-def-body names arities bindings    &lt;br /&gt;                   decrement-argcounts argcounts head argcounts&lt;br /&gt;                   decrement-funcalls argcounts funcalls head argcounts&lt;br /&gt;                   _&lt;br /&gt;                   head tokens&lt;br /&gt;                   tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-try-binding names arities bindings argcounts funcalls tokens&lt;br /&gt;                      name _ . arity =&lt;br /&gt;    == not in bindings, push funcall&lt;br /&gt;    parse-def-body names arities bindings    &lt;br /&gt;                   concat list-encode arity&lt;br /&gt;                          argcounts&lt;br /&gt;                   concat list-encode concat list-encode name&lt;br /&gt;                                             list-encode arity&lt;br /&gt;                          funcalls&lt;br /&gt;                   _&lt;br /&gt;                   head tokens&lt;br /&gt;                   tail tokens.&lt;br /&gt;&lt;br /&gt;parse-def-try-binding names arities bindings argcounts funcalls tokens&lt;br /&gt;                      name bind-list bind-index arity =&lt;br /&gt;    if-equal name head bind-list&lt;br /&gt;             parse-def-emit-bound names arities bindings&lt;br /&gt;                                  argcounts funcalls tokens&lt;br /&gt;                                  bind-index&lt;br /&gt;             parse-def-try-binding names arities bindings&lt;br /&gt;                                   argcounts funcalls tokens&lt;br /&gt;                                   name&lt;br /&gt;                                   tail bind-list&lt;br /&gt;                                   concat 1 bind-index&lt;br /&gt;                                   arity.&lt;br /&gt;&lt;br /&gt;parse-def-emit-bound names arities bindings argcounts funcalls tokens&lt;br /&gt;                     bind-index =&lt;br /&gt;    list-encode if-equal _ argcounts&lt;br /&gt;                         concat 10 bind-index == concat&lt;br /&gt;                         concat 00 bind-index == push&lt;br /&gt;    check-argcounts argcounts funcalls&lt;br /&gt;                    head argcounts&lt;br /&gt;    parse-def-body names arities bindings    &lt;br /&gt;                   decrement-argcounts argcounts head argcounts&lt;br /&gt;                   decrement-funcalls argcounts funcalls head argcounts&lt;br /&gt;                   _&lt;br /&gt;                   head tokens&lt;br /&gt;                   tail tokens.&lt;br /&gt;&lt;br /&gt;end-constant argcounts _ = _.&lt;br /&gt;end-constant argcounts bits =&lt;br /&gt;    list-encode if-equal argcounts _&lt;br /&gt;                         concat 110 bits  == concat constant&lt;br /&gt;                         concat 010 bits. == push constant&lt;br /&gt;&lt;br /&gt;check-argcounts _ . . = _.&lt;br /&gt;check-argcounts argcounts funcalls _ =&lt;br /&gt;    list-encode concat if-equal _ tail argcounts&lt;br /&gt;                                111_ == concat funcall&lt;br /&gt;                                011  == push funcall&lt;br /&gt;                       head funcalls&lt;br /&gt;    check-argcounts tail argcounts tail funcalls&lt;br /&gt;                    head tail argcounts.&lt;br /&gt;check-argcounts argcounts funcalls 1_ =&lt;br /&gt;    list-encode concat if-equal _ tail argcounts&lt;br /&gt;                                111_ == concat funcall&lt;br /&gt;                                011  == push funcall&lt;br /&gt;                       head funcalls&lt;br /&gt;    check-argcounts tail argcounts tail funcalls&lt;br /&gt;                    head tail argcounts.&lt;br /&gt;check-argcounts . . . = _.&lt;br /&gt;&lt;br /&gt;decrement-argcounts _ . = _.&lt;br /&gt;decrement-argcounts argcounts _ =&lt;br /&gt;    decrement-argcounts tail argcounts head tail argcounts.&lt;br /&gt;decrement-argcounts argcounts 1_ =&lt;br /&gt;    decrement-argcounts tail argcounts head tail argcounts.&lt;br /&gt;decrement-argcounts argcounts 1argcount =&lt;br /&gt;    list-encode argcount&lt;br /&gt;    tail argcounts.&lt;br /&gt;&lt;br /&gt;decrement-funcalls _ . . = _.&lt;br /&gt;decrement-funcalls argcounts funcalls _ =&lt;br /&gt;    decrement-funcalls tail argcounts tail funcalls head tail argcounts.&lt;br /&gt;decrement-funcalls argcounts funcalls 1_ =&lt;br /&gt;    decrement-funcalls tail argcounts tail funcalls head tail argcounts.&lt;br /&gt;decrement-funcalls . funcalls . = funcalls.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;Bit code interpreter&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;== 01_ bitcode interpreter&lt;br /&gt;&lt;br /&gt;bitcode bitcode arg arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 =&lt;br /&gt;    interpret-bitcode bitcode&lt;br /&gt;                      arglist arg arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9.&lt;br /&gt;&lt;br /&gt;interpret-bitcode bitcode args =&lt;br /&gt;    apply head tail tail bitcode == list of function names&lt;br /&gt;          head tail tail tail bitcode == list of functions&lt;br /&gt;          alist-lookup head bitcode == main function name&lt;br /&gt;                       head tail tail bitcode == list of function names&lt;br /&gt;                       head tail tail tail bitcode == list of functions&lt;br /&gt;          push-arguments head tail bitcode == main function arity&lt;br /&gt;                         args&lt;br /&gt;                         empty-stack.&lt;br /&gt;&lt;br /&gt;arglist arg arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 =&lt;br /&gt;    list-encode arg  list-encode arg2 list-encode arg3&lt;br /&gt;    list-encode arg4 list-encode arg5 list-encode arg6&lt;br /&gt;    list-encode arg7 list-encode arg8 list-encode arg9.&lt;br /&gt;&lt;br /&gt;push-arguments _ . stack = stack.&lt;br /&gt;push-arguments 1count args stack =&lt;br /&gt;    push-arguments count&lt;br /&gt;                   tail args&lt;br /&gt;                   push head args&lt;br /&gt;                        stack.&lt;br /&gt;&lt;br /&gt;apply fnames functions function args =&lt;br /&gt;    match fnames functions args&lt;br /&gt;          head function&lt;br /&gt;          tail function.&lt;br /&gt;&lt;br /&gt;match fnames functions args _ defs = error _. == pattern match failed&lt;br /&gt;&lt;br /&gt;match fnames functions args def defs =&lt;br /&gt;    match2 fnames functions args defs&lt;br /&gt;           head head def == first pattern&lt;br /&gt;           tail head def == remaining patterns&lt;br /&gt;           tail def == body&lt;br /&gt;           empty-stack == bindings&lt;br /&gt;           args.&lt;br /&gt;&lt;br /&gt;match2 fnames functions saved-args defs&lt;br /&gt;       _ patterns body bindings args&lt;br /&gt;    = eval fnames functions bindings&lt;br /&gt;           head body&lt;br /&gt;           tail body&lt;br /&gt;           empty-stack.&lt;br /&gt;&lt;br /&gt;== binding&lt;br /&gt;match2 fnames functions saved-args defs&lt;br /&gt;       0pattern-bits patterns body bindings args =&lt;br /&gt;    if-match pattern-bits&lt;br /&gt;             top args&lt;br /&gt;             match2 fnames functions saved-args defs&lt;br /&gt;                    head patterns&lt;br /&gt;                    tail patterns&lt;br /&gt;                    body&lt;br /&gt;                    push drop-head pattern-bits&lt;br /&gt;                                   top args&lt;br /&gt;                         bindings&lt;br /&gt;                    pop args&lt;br /&gt;             match fnames functions saved-args&lt;br /&gt;                   head defs&lt;br /&gt;                   tail defs.&lt;br /&gt;&lt;br /&gt;== literal&lt;br /&gt;match2 fnames functions saved-args defs&lt;br /&gt;       10pattern-bits patterns body bindings args =&lt;br /&gt;    if-equal pattern-bits&lt;br /&gt;             top args&lt;br /&gt;             match2 fnames functions saved-args defs&lt;br /&gt;                    head patterns&lt;br /&gt;                    tail patterns&lt;br /&gt;                    body&lt;br /&gt;                    bindings&lt;br /&gt;                    pop args&lt;br /&gt;             match fnames functions saved-args&lt;br /&gt;                    head defs&lt;br /&gt;                    tail defs.&lt;br /&gt;&lt;br /&gt;== wild&lt;br /&gt;match2 fnames functions saved-args defs&lt;br /&gt;       11pattern-bits patterns body bindings args =&lt;br /&gt;    if-match pattern-bits&lt;br /&gt;             top args&lt;br /&gt;             match2 fnames functions saved-args defs&lt;br /&gt;                    head patterns&lt;br /&gt;                    tail patterns&lt;br /&gt;                    body&lt;br /&gt;                    bindings&lt;br /&gt;                    pop args&lt;br /&gt;             match fnames functions saved-args&lt;br /&gt;                    head defs&lt;br /&gt;                    tail defs.&lt;br /&gt;&lt;br /&gt;eval fnames functions bindings _ ops stack = _.&lt;br /&gt;&lt;br /&gt;== push bound expr&lt;br /&gt;eval fnames functions bindings&lt;br /&gt;     00index ops stack =&lt;br /&gt;    eval fnames functions bindings&lt;br /&gt;         head ops&lt;br /&gt;         tail ops&lt;br /&gt;         push get-binding index bindings&lt;br /&gt;              stack.&lt;br /&gt;&lt;br /&gt;== concat bound expr&lt;br /&gt;eval fnames functions bindings&lt;br /&gt;     10index ops 0. =&lt;br /&gt;    get-binding index bindings&lt;br /&gt;    eval fnames functions bindings&lt;br /&gt;         head ops&lt;br /&gt;         tail ops&lt;br /&gt;         empty-stack.&lt;br /&gt;&lt;br /&gt;get-binding _ bindings = top bindings.&lt;br /&gt;get-binding 1index bindings = get-binding index pop bindings.&lt;br /&gt;&lt;br /&gt;== push literal expr&lt;br /&gt;eval fnames functions bindings&lt;br /&gt;     010bits ops stack =&lt;br /&gt;    eval fnames functions bindings&lt;br /&gt;         head ops&lt;br /&gt;         tail ops&lt;br /&gt;         push bits stack.&lt;br /&gt;&lt;br /&gt;== concat literal expr&lt;br /&gt;eval fnames functions bindings&lt;br /&gt;     110bits ops 0. =&lt;br /&gt;    bits&lt;br /&gt;    eval fnames functions bindings&lt;br /&gt;         head ops&lt;br /&gt;         tail ops&lt;br /&gt;         empty-stack.&lt;br /&gt;&lt;br /&gt;== push funcall expr&lt;br /&gt;eval fnames functions bindings&lt;br /&gt;     011funcall ops stack =&lt;br /&gt;    eval fnames functions bindings&lt;br /&gt;         head ops&lt;br /&gt;         tail ops&lt;br /&gt;         push apply fnames functions&lt;br /&gt;                    alist-lookup head funcall&lt;br /&gt;                                 fnames functions&lt;br /&gt;                    pull-args head tail funcall&lt;br /&gt;                              stack empty-stack&lt;br /&gt;              pop-args head tail funcall&lt;br /&gt;                       stack.&lt;br /&gt;&lt;br /&gt;== concat funcall expr&lt;br /&gt;eval fnames functions bindings&lt;br /&gt;     111funcall ops stack =&lt;br /&gt;    apply fnames functions&lt;br /&gt;          alist-lookup head funcall&lt;br /&gt;                       fnames functions&lt;br /&gt;          pull-args head tail funcall&lt;br /&gt;                    stack empty-stack&lt;br /&gt;    eval fnames functions bindings&lt;br /&gt;         head ops&lt;br /&gt;         tail ops&lt;br /&gt;         pop-args head tail funcall&lt;br /&gt;                  stack.&lt;br /&gt;&lt;br /&gt;pull-args _ . args = args.&lt;br /&gt;pull-args 1count stack args =&lt;br /&gt;    pull-args count&lt;br /&gt;              pop stack&lt;br /&gt;              push top stack&lt;br /&gt;                   args.&lt;br /&gt;&lt;br /&gt;pop-args _ stack = stack.&lt;br /&gt;pop-args 1count stack =&lt;br /&gt;    pop-args count&lt;br /&gt;             pop stack.&lt;br /&gt;&lt;br /&gt;if-match 0x 0y true false = if-match x y true false.&lt;br /&gt;if-match 1x 1y true false = if-match x y true false.&lt;br /&gt;if-match _ . true . = true.&lt;br /&gt;if-match . . . false = false.&lt;br /&gt;&lt;br /&gt;drop-head 0x 0y = drop-head x y.&lt;br /&gt;drop-head 1x 1y = drop-head x y.&lt;br /&gt;drop-head _ y = y.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;Top-level&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;interp in arg arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 =&lt;br /&gt;    interpret-bitcode parse tokenize in&lt;br /&gt;                      arglist arg arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9.&lt;br /&gt;&lt;br /&gt;compile in = parse tokenize in 0000000. == pad to at least an even byte&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;Code size comparisons&lt;/h5&gt;&lt;br /&gt;Since I've implemented multiple 01_ interpreters, here's a comparison of the source code sizes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Haskell - 216 lines, 9k&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Python - 424 lines, 12k&lt;br /&gt;&lt;/li&gt;&lt;li&gt;01_ - 746 lines, 25k&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Java (slow original version) - 782 lines, 25k&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Java (fast new version including compiler to Java) - 1188 lines, 34k&lt;br /&gt;&lt;/li&gt;&lt;li&gt;C - 1527 lines, 37k&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-3493864349175854772?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/3493864349175854772/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/02/here-is-interpreter-for-01-that-i-wrote.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3493864349175854772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3493864349175854772'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/02/here-is-interpreter-for-01-that-i-wrote.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-7833620463868853108</id><published>2010-02-15T00:00:00.001-08:00</published><updated>2010-02-15T00:00:02.635-08:00</updated><title type='text'></title><content type='html'>I had the crazy notion of implementing an &lt;a href="/2009/06/01-programming-language.html"&gt;01_&lt;/a&gt; interpreter in 01_.  One first step would be to come up with some bit-code data structure and write an interpreter for that in 01_, and, to start with, write a compiler from 01_ source code to the bit-code in a sane language like Haskell or Java for testing.  Then, the final step would be to write an 01_ source to the bit code compiler in 01_.&lt;br /&gt;&lt;br /&gt;Which leads to data structures in 01_.  The only data type in 01_ is the list of bits, and only pattern matching and list concatenation are the available operations.  Higher-level data structures can be built on that, and that's what I'm writing about.&lt;br /&gt;&lt;br /&gt;I had an idea on how to make lists of arbitrary (finite) data.  However, 01_ programs can deal with infinite bit lists, so I came up with an idea on how to make a stack of potentially infinite bit lists as well.&lt;br /&gt;&lt;br /&gt;An 01_ interpreter would need some dictionary datatype, so association lists can be built on top of the lists.  One way would be to use nested lists.  Another would be to use a pair of lists.&lt;br /&gt;&lt;h5&gt;List of arbitrary finite data&lt;/h5&gt;&lt;br /&gt;The scheme uses a control bit, where 1 means a data bit follows, and there are more bits, and 0 means the end of the list.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;== first item in the list&lt;br /&gt;head 0. = _.&lt;br /&gt;head 11rest = 1 head rest.&lt;br /&gt;head 10rest = 0 head rest.&lt;br /&gt;head _ = _.&lt;br /&gt;&lt;br /&gt;== the list with the first item removed&lt;br /&gt;tail 0rest = rest.&lt;br /&gt;tail 11rest = tail rest.&lt;br /&gt;tail 10rest = tail rest.&lt;br /&gt;tail _ = _.&lt;br /&gt;&lt;br /&gt;== the list with a new item added to the front (or end)&lt;br /&gt;add data list = list-encode data list.&lt;br /&gt;add-to-end data list = list list-encode data.&lt;br /&gt;&lt;br /&gt;list-encode _ = 0.&lt;br /&gt;list-encode 1x = 11 encode x.&lt;br /&gt;list-encode 0x = 10 encode x.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;Stack of potentially infinite lists&lt;/h5&gt;&lt;br /&gt;Let n = the number of items in the stack.  The stack data structure starts with n 1s, followed by a 0, followed the stack data.&lt;br /&gt;&lt;br /&gt;The stack data starts with the first bit of every item in the stack, followed by the second bit of every item in the stack, followed by the third bit, etc.&lt;br /&gt;&lt;br /&gt;Each stack bit starts with the control bit for the top bit in the top item in the stack, where a 1 is followed by the data bit of the item, and a 0 means the item has no more bits, which is followed by next item in the stack, etc all the way to the bottom of the stack.&lt;br /&gt;&lt;br /&gt;This implementation would undoubtedly be hugely inefficient.  When dealing with the largest item yet to be in the stack, the entire history of operations on the stack will have to be unwound for the rightmost bits.  The 1 item optimization in pop helps a little by limiting the history that has to be unwound to the last time the stack was empty.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;== new empty stack&lt;br /&gt;empty = 0_.&lt;br /&gt;&lt;br /&gt;== number of items in the stack (in base 1)&lt;br /&gt;stack-count 0stack = _.&lt;br /&gt;stack-count 1stack = 1 stack-count stack.&lt;br /&gt;&lt;br /&gt;drop-stack-count 0stack = stack.&lt;br /&gt;drop-stack-count 1stack = drop-stack-count stack.&lt;br /&gt;&lt;br /&gt;== top of the stack&lt;br /&gt;top 0. = _. == stack underflow&lt;br /&gt;top stack =&lt;br /&gt;    top' decrement-count stack-count stack&lt;br /&gt;         drop-stack-count stack.&lt;br /&gt;&lt;br /&gt;top' count 0stack-data = _.&lt;br /&gt;top' count 10stack-data =&lt;br /&gt;    0 top' count&lt;br /&gt;           drop-stack-bit count stack-data.&lt;br /&gt;top' count 11stack-data =&lt;br /&gt;    1 top' count&lt;br /&gt;           drop-stack-bit count stack-data.&lt;br /&gt;&lt;br /&gt;decrement-count 1count = count.&lt;br /&gt;&lt;br /&gt;drop-stack-bit _ stack-data = stack-data.&lt;br /&gt;drop-stack-bit 1count  0stack-data = drop-stack-bit count stack-data.&lt;br /&gt;drop-stack-bit 1count 10stack-data = drop-stack-bit count stack-data.&lt;br /&gt;drop-stack-bit 1count 11stack-data = drop-stack-bit count stack-data.&lt;br /&gt;&lt;br /&gt;== returns stack with data pushed on top&lt;br /&gt;push data stack =&lt;br /&gt;    1 stack-count stack 0&lt;br /&gt;    push' data count drop-stack-count stack.&lt;br /&gt;&lt;br /&gt;push' _ count stack-data =&lt;br /&gt;    0 take-stack-bit count stack-data&lt;br /&gt;      push' _ count drop-stack-bit count stack-data.&lt;br /&gt;push' 0data count stack-data =&lt;br /&gt;    10 take-stack-bit count stack-data&lt;br /&gt;       push' data count drop-stack-bit count stack-data.&lt;br /&gt;push' 1data count stack-data =&lt;br /&gt;    11 take-stack-bit count stack-data&lt;br /&gt;       push' data count drop-stack-bit count stack-data.&lt;br /&gt;&lt;br /&gt;take-stack-bit _ . = _.&lt;br /&gt;take-stack-bit 1count  0stack-data =  0 take-stack-bit count stack-data.&lt;br /&gt;take-stack-bit 1count 10stack-data = 10 take-stack-bit count stack-data.&lt;br /&gt;take-stack-bit 1count 11stack-data = 11 take-stack-bit count stack-data.&lt;br /&gt;&lt;br /&gt;== returns stack with the top item popped&lt;br /&gt;pop 0. = 0_. == stack underflow&lt;br /&gt;pop 10. = 0_. == 1 item optimization&lt;br /&gt;pop 1stack =&lt;br /&gt;    stack-count stack 0&lt;br /&gt;    pop' stack-count stack&lt;br /&gt;         drop-stack-count stack.&lt;br /&gt;&lt;br /&gt;pop' count 0stack-data =&lt;br /&gt;    take-stack-bit count stack-data&lt;br /&gt;    pop' count&lt;br /&gt;         drop-stack-bit count stack-data.&lt;br /&gt;pop' count 10stack-data =&lt;br /&gt;    take-stack-bit count stack-data&lt;br /&gt;    pop' count&lt;br /&gt;         drop-stack-bit count stack-data.&lt;br /&gt;pop' count 11stack-data =&lt;br /&gt;    take-stack-bit count stack-data&lt;br /&gt;    pop' count&lt;br /&gt;         drop-stack-bit count stack-data.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;Association lists&lt;/h5&gt;&lt;br /&gt;For implementing association lists, a pair of lists would be more efficient, but more complicated and error-prone to use than nested lists.  I'll include implementations of both, but I'd probably use a pair of lists.&lt;br /&gt;&lt;br /&gt;Association list using nested lists.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;lookup key alist = try-lookup key head alist lookup key tail alist.&lt;br /&gt;lookup . _ = _.&lt;br /&gt;&lt;br /&gt;try-lookup key pair fail = if-equal key head pair head tail pair fail.&lt;br /&gt;&lt;br /&gt;add-alist key data alist = add add key add data _ alist.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Association list using a pair of lists.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;lookup key klist dlist =&lt;br /&gt;    if-equal key head klist head dlist lookup key tail klist tail dlist.&lt;br /&gt;lookup . _ . = _.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;They both use if-equal, defined here.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;if-equal 0x 0y true false = if-equal x y true false.&lt;br /&gt;if-equal 1x 1y true false = if-equal x y true false.&lt;br /&gt;if-equal _ _ true . = true.&lt;br /&gt;if-equal . . . false = false.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;More association lists&lt;/h5&gt;&lt;br /&gt;These will use a pair of lists, one for the keys, and one for the data.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;== test if key is present&lt;br /&gt;if-has-key key _ true false = false.&lt;br /&gt;if-has-key key klist true false =&lt;br /&gt;    if-equal key head klist true if-has-key key tail klist true false.&lt;br /&gt;&lt;br /&gt;== append to data associated with key&lt;br /&gt;append-alist key data klist dlist =&lt;br /&gt;    if-has-key key klist&lt;br /&gt;               append-alist' key data klist dlist&lt;br /&gt;               add data dlist.&lt;br /&gt;&lt;br /&gt;append-alist' key data klist dlist =&lt;br /&gt;    if-equal key head klist&lt;br /&gt;             append-alist-matching data dlist&lt;br /&gt;             append-alist-nonmatching key data klist dlist.&lt;br /&gt;&lt;br /&gt;append-alist-matching data dlist =&lt;br /&gt;    add add-to-end data head dlist&lt;br /&gt;        tail dlist.&lt;br /&gt;&lt;br /&gt;append-alist-nonmatching key data klist dlist =&lt;br /&gt;    head dlist&lt;br /&gt;    append-alist' key data tail klist tail dlist.&lt;br /&gt;&lt;br /&gt;append-alist-key key klist =&lt;br /&gt;    if-has-key key klist&lt;br /&gt;               klist&lt;br /&gt;               add key klist.&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-7833620463868853108?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/7833620463868853108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/02/i-had-crazy-notion-of-implementing-01.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7833620463868853108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/7833620463868853108'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/02/i-had-crazy-notion-of-implementing-01.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-8379102795345813132</id><published>2010-02-08T00:00:00.001-08:00</published><updated>2010-02-08T00:00:06.493-08:00</updated><title type='text'></title><content type='html'>I had the idea of making a compiler for the &lt;a href="/2009/06/01-programming-language.html"&gt;01_ programming language&lt;/a&gt; that compiled to the Java Virtual Machine (JVM).  For starters, I wrote a few classes for the runtime library.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;rt01_.val: For values in the only datatype in 01_, a list of bits.  I included the trampoline() method, which must be called before evaluation, to avoid stack overflows, and to allow discarded values to be garbage collected.&lt;br /&gt;&lt;li&gt;rt01_.constant: For literal constants.  I decided on representing the constant as a string of 0 and 1, since strings are the only way to represent arbitrary length constants in the Java class file format without needing initialization code to construct it.  Additionally, the same string in the constant pool could be reused as the name of the field holding that constant.  Compiling to Java means the field names have to be valid Java identifiers, but they don't have to be when compiling directly to Java class files.&lt;br /&gt;&lt;li&gt;rt01_.concat: For the only operation in 01_, list concatenation.&lt;br /&gt;&lt;li&gt;rt01_.input: For reading input as a list of bits.&lt;br /&gt;&lt;li&gt;rt01_.function: To be extended by classes representing 01_ functions.  They should receive their arguments in the constructor, and build their results in eval(), and have a main() for being invoked from the command line.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Then, to test it out, I started with using it to write an interpreter.  At first, it was getting OutOfMemoryErrors.  I had written Function.eval() as&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    public rt01_.function eval(final rt01_.val[] args) {&lt;br /&gt;        return new rt01_.function() {&lt;br /&gt;            protected rt01_.val eval() {&lt;br /&gt;                for (Def def : defs) {&lt;br /&gt;                    rt01_.val val = def.eval(args);&lt;br /&gt;                    if (val != null)&lt;br /&gt;                        return val;&lt;br /&gt;                }&lt;br /&gt;                throw new RuntimeException(...);&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The capture of args in the anonymous class prevented the arguments from being garbage collected.  Once I fixed that, the interpreter ran much faster than my previous interpreter in Java, faster than my interpreter in C, and even slightly faster than my interpreter in Haskell.  Once I implemented the interpreter, it was a simple matter to extend it to compile to Java.  The compiled code was maybe 5-10% faster than the interpreter.&lt;br /&gt;&lt;br /&gt;I want to compile directly to class files rather than to Java, which will take a lot more work.  This interpreter and compiler to Java was pretty much a weekend hack.  I imagine the generated code would be pretty much the same as compiling to Java.  The main difference is that the function names wouldn't have to be as heavily mangled, since they would no longer have to be valid Java identifiers, and would not have to avoid Java reserved words.  Also, the SourceFile and LineNumberTable attributes could point to the 01_ source.&lt;br /&gt;&lt;br /&gt;Here is the runtime:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package rt01_;&lt;br /&gt;&lt;br /&gt;public abstract class val {&lt;br /&gt;    protected val trampoline() {&lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public boolean nil() {&lt;br /&gt;        return false;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public abstract boolean head();&lt;br /&gt;    public abstract val tail();&lt;br /&gt;&lt;br /&gt;    public static final val NIL = new val() {&lt;br /&gt;            public boolean nil() {&lt;br /&gt;                return true;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public boolean head() {&lt;br /&gt;                throw new NullPointerException();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public val tail() {&lt;br /&gt;                throw new NullPointerException();&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;    public static val trampoline(val val) {&lt;br /&gt;        for (val v = val.trampoline(); v != null; v = val.trampoline())&lt;br /&gt;            val = v;&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package rt01_;&lt;br /&gt;&lt;br /&gt;public class constant extends val {&lt;br /&gt;    private String bits;&lt;br /&gt;    private int index;&lt;br /&gt;    private val tail = null;&lt;br /&gt;&lt;br /&gt;    public constant(String bits) {&lt;br /&gt;        this(bits, 0);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private constant(String bits, int index) {&lt;br /&gt;        this.bits = bits;&lt;br /&gt;        this.index = index;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected val trampoline() {&lt;br /&gt;        if (index &amp;gt;= bits.length())&lt;br /&gt;            return NIL;&lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public boolean head() {&lt;br /&gt;        return '1' == bits.charAt(index);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public val tail() {&lt;br /&gt;        if (tail == null) {&lt;br /&gt;            if (index + 1 &amp;lt; bits.length())&lt;br /&gt;                tail = new constant(bits, index + 1);&lt;br /&gt;            else&lt;br /&gt;                tail = NIL;&lt;br /&gt;        }&lt;br /&gt;        return tail;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package rt01_;&lt;br /&gt;&lt;br /&gt;public class concat extends val {&lt;br /&gt;    private val first;&lt;br /&gt;    private val second;&lt;br /&gt;    private val tail = null;&lt;br /&gt;&lt;br /&gt;    public concat(val first, val second) {&lt;br /&gt;        this.first = first;&lt;br /&gt;        this.second = second;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected val trampoline() {&lt;br /&gt;        first = trampoline(first);&lt;br /&gt;        if (first.nil())&lt;br /&gt;            return second;&lt;br /&gt;        else&lt;br /&gt;            return null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public boolean head() {&lt;br /&gt;        return first.head();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public val tail() {&lt;br /&gt;        if (tail == null)&lt;br /&gt;            tail = new concat(first.tail(), second);&lt;br /&gt;        return tail;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package rt01_;&lt;br /&gt;&lt;br /&gt;import java.io.FileInputStream;&lt;br /&gt;import java.io.InputStream;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;&lt;br /&gt;public class input extends val {&lt;br /&gt;    private InputStream in;&lt;br /&gt;    private int byt;&lt;br /&gt;    private int bit;&lt;br /&gt;    private val tail = null;&lt;br /&gt;&lt;br /&gt;    public input(String file) throws IOException {&lt;br /&gt;        this(new FileInputStream(file));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public input(InputStream in) {&lt;br /&gt;        this(in, -1, 0);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private input(InputStream in, int byt, int bit) {&lt;br /&gt;        this.in = in;&lt;br /&gt;        this.byt = byt;&lt;br /&gt;        this.bit = bit;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected val trampoline() {&lt;br /&gt;        if (bit == 0) {&lt;br /&gt;            try {&lt;br /&gt;                byt = in.read();&lt;br /&gt;            } catch (IOException e) {&lt;br /&gt;                throw new RuntimeException(e);&lt;br /&gt;            }&lt;br /&gt;            if (byt &amp;lt; 0)&lt;br /&gt;                return NIL;&lt;br /&gt;            bit = 128;&lt;br /&gt;        }&lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public boolean head() {&lt;br /&gt;        return (byt &amp;amp; bit) != 0;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public val tail() {&lt;br /&gt;        if (tail == null)&lt;br /&gt;            tail = new input(in, byt, bit &amp;gt;&amp;gt; 1);&lt;br /&gt;        return tail;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package rt01_;&lt;br /&gt;&lt;br /&gt;import java.io.OutputStream;&lt;br /&gt;import java.io.PrintStream;&lt;br /&gt;&lt;br /&gt;public abstract class function extends val {&lt;br /&gt;    private val val = null;&lt;br /&gt;&lt;br /&gt;    protected val trampoline() {&lt;br /&gt;        if (val == null)&lt;br /&gt;            val = eval();&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected abstract val eval();&lt;br /&gt;&lt;br /&gt;    public boolean nil() {&lt;br /&gt;        throw new RuntimeException();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public boolean head() {&lt;br /&gt;        throw new RuntimeException();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public val tail() {&lt;br /&gt;        throw new RuntimeException();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String[] args, int arity, String name) throws Exception {&lt;br /&gt;        Class&amp;lt;?&amp;gt;[] types = new Class&amp;lt;?&amp;gt;[arity];&lt;br /&gt;        for (int i = 0; i &amp;lt; arity; i++)&lt;br /&gt;            types[i] = val.class;&lt;br /&gt;        int index = 0;&lt;br /&gt;        boolean bits = false;&lt;br /&gt;        if (args.length &amp;gt; 0 &amp;amp;&amp;amp; "-bits".equals(args[0])) {&lt;br /&gt;            index = 1;&lt;br /&gt;            bits = true;&lt;br /&gt;        }&lt;br /&gt;        val val = (function) Class.forName(name).getDeclaredConstructor(types).newInstance((Object[]) args(args, arity, index));&lt;br /&gt;        if (bits)&lt;br /&gt;            writeBits(val, System.out);&lt;br /&gt;        else&lt;br /&gt;            write(val, System.out);&lt;br /&gt;        System.out.flush();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static val[] args(String[] args, int arity, int index) throws Exception {&lt;br /&gt;        val[] vals = new val[arity];&lt;br /&gt;        val stdin = null;&lt;br /&gt;        for (int i = 0; i &amp;lt; arity; i++) {&lt;br /&gt;            if (index + i &amp;lt; args.length) {&lt;br /&gt;                if (!"-".equals(args[index + i])) {&lt;br /&gt;                    vals[i] = new input(args[index + i]);&lt;br /&gt;                } else {&lt;br /&gt;                    if (stdin == null)&lt;br /&gt;                        stdin = new input(System.in);&lt;br /&gt;                    vals[i] = stdin;&lt;br /&gt;                }&lt;br /&gt;            } else if (stdin == null) {&lt;br /&gt;                stdin = new input(System.in);&lt;br /&gt;                vals[i] = stdin;&lt;br /&gt;            } else {&lt;br /&gt;                vals[i] = NIL;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return vals;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void writeBits(val val, PrintStream out) throws Exception {&lt;br /&gt;        for (;;) {&lt;br /&gt;            val = trampoline(val);&lt;br /&gt;            if (val.nil())&lt;br /&gt;                break;&lt;br /&gt;            out.print(val.head() ? "1" : "0");&lt;br /&gt;            val = val.tail();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void write(val val, OutputStream out) throws Exception {&lt;br /&gt;        int byt = 0;&lt;br /&gt;        int bit = 128;&lt;br /&gt;        for (;;) {&lt;br /&gt;            val = trampoline(val);&lt;br /&gt;            if (val.nil())&lt;br /&gt;                break;&lt;br /&gt;            byt |= val.head() ? bit : 0;&lt;br /&gt;            bit &amp;gt;&amp;gt;= 1;&lt;br /&gt;            if (bit == 0) {&lt;br /&gt;                out.write(byt);&lt;br /&gt;                byt = 0;&lt;br /&gt;                bit = 128;&lt;br /&gt;            }&lt;br /&gt;            val = val.tail();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here is the interpreter and compiler to Java:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class BoundExpr extends Expr {&lt;br /&gt;    private int index;&lt;br /&gt;&lt;br /&gt;    public BoundExpr(Token token, int index) {&lt;br /&gt;        super(token);&lt;br /&gt;        this.index = index;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public rt01_.val eval(rt01_.val[] bindings) {&lt;br /&gt;        return bindings[index];&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getIndex() {&lt;br /&gt;        return index;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;import java.io.FileWriter;&lt;br /&gt;import java.io.PrintWriter;&lt;br /&gt;&lt;br /&gt;public class Compiler {&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        Parser parser = new Parser();&lt;br /&gt;        for (String arg : args)&lt;br /&gt;            parser.add(arg);&lt;br /&gt;        for (Function function : parser.getFunctions().values()) {&lt;br /&gt;            PrintWriter out = new PrintWriter(new FileWriter(function.getMangledName() + ".java"));&lt;br /&gt;            function.compile(out);&lt;br /&gt;            out.flush();&lt;br /&gt;            out.close();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class ConcatExpr extends Expr {&lt;br /&gt;    private Expr first;&lt;br /&gt;    private Expr second;&lt;br /&gt;&lt;br /&gt;    public ConcatExpr(Expr first, Expr second) {&lt;br /&gt;        super(first.getToken());&lt;br /&gt;        this.first = first;&lt;br /&gt;        this.second = second;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public rt01_.val eval(rt01_.val[] bindings) {&lt;br /&gt;        return new rt01_.concat(first.eval(bindings), second.eval(bindings));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Expr getFirst() {&lt;br /&gt;        return first;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Expr getSecond() {&lt;br /&gt;        return second;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;public class ConstantExpr extends Expr {&lt;br /&gt;    private String bits;&lt;br /&gt;    private rt01_.constant val;&lt;br /&gt;&lt;br /&gt;    public ConstantExpr(Token token, boolean[] bits) {&lt;br /&gt;        super(token);&lt;br /&gt;        StringBuilder sb = new StringBuilder();&lt;br /&gt;        for (boolean bit : bits)&lt;br /&gt;            sb.append(bit ? "1" : "0");&lt;br /&gt;        this.bits = sb.toString();&lt;br /&gt;        val = new rt01_.constant(this.bits);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public rt01_.val eval(rt01_.val[] bindings) {&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getBits() {&lt;br /&gt;        return bits;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;import java.io.PrintWriter;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;public class Def {&lt;br /&gt;    private Token name;&lt;br /&gt;    private Pattern[] patterns;&lt;br /&gt;    private Token[] body;&lt;br /&gt;&lt;br /&gt;    private int bindingCount;&lt;br /&gt;    private Expr expr;&lt;br /&gt;&lt;br /&gt;    public Def(Token name, Pattern[] patterns, Token[] body) {&lt;br /&gt;        this.name = name;&lt;br /&gt;        this.patterns = patterns;&lt;br /&gt;        this.body = body;&lt;br /&gt;&lt;br /&gt;        bindingCount = 0;&lt;br /&gt;        for (Pattern pattern : patterns)&lt;br /&gt;            if (pattern.isBinding())&lt;br /&gt;                bindingCount++;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getArity() {&lt;br /&gt;        return patterns.length;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Token getName() {&lt;br /&gt;        return name;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private class ParseState {&lt;br /&gt;        int index;&lt;br /&gt;        Expr expr;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void parse(Map&amp;lt;String,Function&amp;gt; functions) {&lt;br /&gt;        if (body.length == 0) {&lt;br /&gt;            expr = new ConstantExpr(name, new boolean[0]);&lt;br /&gt;        } else {&lt;br /&gt;            ParseState state = new ParseState();&lt;br /&gt;            state.index = 0;&lt;br /&gt;            state.expr = null;&lt;br /&gt;            parse(functions, state);&lt;br /&gt;            expr = state.expr;&lt;br /&gt;        }&lt;br /&gt;        body = null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void parse(Map&amp;lt;String,Function&amp;gt; functions, ParseState state) {&lt;br /&gt;        state.expr = null;&lt;br /&gt;        parse1(functions, state);&lt;br /&gt;        if (state.index &amp;lt; body.length) {&lt;br /&gt;            Expr first = state.expr;&lt;br /&gt;            parse(functions, state);&lt;br /&gt;            state.expr = new ConcatExpr(first, state.expr);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void parse1(Map&amp;lt;String,Function&amp;gt; functions, ParseState state) {&lt;br /&gt;        Token token = body[state.index];&lt;br /&gt;        switch (token.getType()) {&lt;br /&gt;        case EQUALS: case DOT:&lt;br /&gt;            assert false;&lt;br /&gt;            throw new RuntimeException();&lt;br /&gt;        case ZERO: case ONE: case NIL:&lt;br /&gt;            parseConstant(token, state);&lt;br /&gt;            return;&lt;br /&gt;        case SYMBOL:&lt;br /&gt;            state.index++;&lt;br /&gt;            state.expr = binding(token);&lt;br /&gt;            if (state.expr != null)&lt;br /&gt;                return;&lt;br /&gt;            if (!functions.containsKey(token.getSymbol()))&lt;br /&gt;                throw new RuntimeException(token.getLocation() + ": unknown function: " + token.getSymbol());&lt;br /&gt;            Function function = functions.get(token.getSymbol());&lt;br /&gt;            Expr[] args = new Expr[function.getArity()];&lt;br /&gt;            for (int i = 0; i &amp;lt; args.length; i++) {&lt;br /&gt;                parse1(functions, state);&lt;br /&gt;                args[i] = state.expr;&lt;br /&gt;            }&lt;br /&gt;            state.expr = new FuncallExpr(token, function, args);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void parseConstant(Token token, ParseState state) {&lt;br /&gt;        ArrayList&amp;lt;Boolean&amp;gt; bits = new ArrayList&amp;lt;Boolean&amp;gt;();&lt;br /&gt;        loop: while (state.index &amp;lt; body.length) {&lt;br /&gt;            switch (body[state.index].getType()) {&lt;br /&gt;            case ZERO:&lt;br /&gt;                state.index++;&lt;br /&gt;                bits.add(false);&lt;br /&gt;                break;&lt;br /&gt;            case ONE:&lt;br /&gt;                state.index++;&lt;br /&gt;                bits.add(true);&lt;br /&gt;                break;&lt;br /&gt;            case NIL:&lt;br /&gt;                state.index++;&lt;br /&gt;            default:&lt;br /&gt;                break loop;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        state.expr = new ConstantExpr(token, DefReader.toBitArray(bits));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private BoundExpr binding(Token token) {&lt;br /&gt;        int bindingIndex = 0;&lt;br /&gt;        for (Pattern pattern : patterns) {&lt;br /&gt;            if (!pattern.isBinding())&lt;br /&gt;                continue;&lt;br /&gt;            if (pattern.getToken().getSymbol().equals(token.getSymbol()))&lt;br /&gt;                return new BoundExpr(token, bindingIndex);&lt;br /&gt;            bindingIndex++;&lt;br /&gt;        }&lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Expr getExpr() {&lt;br /&gt;        return expr;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public rt01_.val eval(rt01_.val[] args) {&lt;br /&gt;        assert args.length == patterns.length;&lt;br /&gt;        rt01_.val[] bindings = new rt01_.val[bindingCount];&lt;br /&gt;        int bindingIndex = 0;&lt;br /&gt;        for (int i = 0; i &amp;lt; args.length; i++) {&lt;br /&gt;            rt01_.val val = patterns[i].match(args[i]);&lt;br /&gt;            if (val == null)&lt;br /&gt;                return null;&lt;br /&gt;            if (patterns[i].isBinding())&lt;br /&gt;                bindings[bindingIndex++] = val;&lt;br /&gt;        }&lt;br /&gt;        return expr.eval(bindings);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void compile(int n, PrintWriter out) throws Exception {&lt;br /&gt;        out.print("    private rt01_.val m");&lt;br /&gt;        out.print(n);&lt;br /&gt;        out.println("() {");&lt;br /&gt;        if (patterns.length &amp;gt; 0)&lt;br /&gt;            out.println("        rt01_.val val;");&lt;br /&gt;        int bindingIndex = 0;&lt;br /&gt;        for (int i = 0; i &amp;lt; patterns.length; i++) {&lt;br /&gt;            Pattern pattern = patterns[i];&lt;br /&gt;            boolean[] bits = pattern.getBits();&lt;br /&gt;            if (bits.length &amp;gt; 0) {&lt;br /&gt;                out.print("        a");&lt;br /&gt;                out.print(i);&lt;br /&gt;                out.print(" = trampoline(a");&lt;br /&gt;                out.print(i);&lt;br /&gt;                out.println(");");&lt;br /&gt;            }&lt;br /&gt;            out.print("        val = a");&lt;br /&gt;            out.print(i);&lt;br /&gt;            out.println(";");&lt;br /&gt;            boolean start = true;&lt;br /&gt;            for (boolean bit : bits) {&lt;br /&gt;                if (start)&lt;br /&gt;                    start = false;&lt;br /&gt;                else&lt;br /&gt;                    out.println("        val = trampoline(val);");&lt;br /&gt;                out.print("        if (val.nil() || ");&lt;br /&gt;                if (bit) out.print("!");&lt;br /&gt;                out.println("val.head()) return null;");&lt;br /&gt;                out.println("        val = val.tail();");&lt;br /&gt;            }&lt;br /&gt;            if (pattern.isLiteral()) {&lt;br /&gt;                out.println("        val = trampoline(val);");&lt;br /&gt;                out.println("        if (!val.nil()) return null;");&lt;br /&gt;            } else if (pattern.isBinding()) {&lt;br /&gt;                out.print("        rt01_.val b");&lt;br /&gt;                out.print(bindingIndex);&lt;br /&gt;                out.println(" = val;");&lt;br /&gt;                bindingIndex++;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        out.print("        return ");&lt;br /&gt;        compileExpr(expr, out);&lt;br /&gt;        out.println(";");&lt;br /&gt;        out.println("    }");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void compileExpr(Expr e, PrintWriter out) throws Exception {&lt;br /&gt;        if (e instanceof BoundExpr) {&lt;br /&gt;            out.print("b");&lt;br /&gt;            out.print(((BoundExpr) e).getIndex());&lt;br /&gt;        } else if (e instanceof ConstantExpr) {&lt;br /&gt;            out.print("_");&lt;br /&gt;            out.print(((ConstantExpr) e).getBits());&lt;br /&gt;        } else if (e instanceof ConcatExpr) {&lt;br /&gt;            out.print("new rt01_.concat(");&lt;br /&gt;            compileExpr(((ConcatExpr) e).getFirst(), out);&lt;br /&gt;            out.print(",");&lt;br /&gt;            compileExpr(((ConcatExpr) e).getSecond(), out);&lt;br /&gt;            out.print(")");&lt;br /&gt;        } else if (e instanceof FuncallExpr) {&lt;br /&gt;            out.print("new ");&lt;br /&gt;            out.print(((FuncallExpr) e).getFunction().getMangledName());&lt;br /&gt;            out.print("(");&lt;br /&gt;            boolean start = true;&lt;br /&gt;            for (Expr arg : ((FuncallExpr) e).getArgs()) {&lt;br /&gt;                if (start)&lt;br /&gt;                    start = false;&lt;br /&gt;                else&lt;br /&gt;                    out.print(",");&lt;br /&gt;                compileExpr(arg, out);&lt;br /&gt;            }&lt;br /&gt;            out.print(")");&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.Iterator;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;public class DefReader implements Iterator&amp;lt;Def&amp;gt; {&lt;br /&gt;    private Iterator&amp;lt;Token&amp;gt; tokenizer;&lt;br /&gt;    private Def def = null;&lt;br /&gt;&lt;br /&gt;    public DefReader(Iterator&amp;lt;Token&amp;gt; tokenizer) {&lt;br /&gt;        this.tokenizer = tokenizer;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public boolean hasNext() {&lt;br /&gt;        if (def == null)&lt;br /&gt;            def = readNext();&lt;br /&gt;        return def != null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Def next() {&lt;br /&gt;        if (def == null)&lt;br /&gt;            return readNext();&lt;br /&gt;        Def result = def;&lt;br /&gt;        def = null;&lt;br /&gt;        return result;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void remove() {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private Def readNext() {&lt;br /&gt;        if (!tokenizer.hasNext())&lt;br /&gt;            return null;&lt;br /&gt;        Token name = tokenizer.next();&lt;br /&gt;        if (name.getType() != Token.Type.SYMBOL)&lt;br /&gt;            throw new RuntimeException(name.getLocation() + ": symbol expected");&lt;br /&gt;        ArrayList&amp;lt;Pattern&amp;gt; patterns = readPatterns(name);&lt;br /&gt;        ArrayList&amp;lt;Token&amp;gt; body = new ArrayList&amp;lt;Token&amp;gt;();&lt;br /&gt;        for (;;) {&lt;br /&gt;            if (!tokenizer.hasNext())&lt;br /&gt;                throw new RuntimeException(name.getLocation() + ": incomplete definition");&lt;br /&gt;            Token token = tokenizer.next();&lt;br /&gt;            if (token.getType() == Token.Type.DOT)&lt;br /&gt;                break;&lt;br /&gt;            body.add(token);&lt;br /&gt;        }&lt;br /&gt;        return new Def(name, patterns.toArray(new Pattern[patterns.size()]), body.toArray(new Token[body.size()]));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private ArrayList&amp;lt;Pattern&amp;gt; readPatterns(Token name) {&lt;br /&gt;        ArrayList&amp;lt;Pattern&amp;gt; patterns = new ArrayList&amp;lt;Pattern&amp;gt;();&lt;br /&gt;        ArrayList&amp;lt;Boolean&amp;gt; bits = new ArrayList&amp;lt;Boolean&amp;gt;();&lt;br /&gt;        Token startToken = null;&lt;br /&gt;        for (;;) {&lt;br /&gt;            if (!tokenizer.hasNext())&lt;br /&gt;                throw new RuntimeException(name.getLocation() + ": incomplete definition");&lt;br /&gt;            Token token = tokenizer.next();&lt;br /&gt;            if (startToken == null)&lt;br /&gt;                startToken = token;&lt;br /&gt;            switch (token.getType()) {&lt;br /&gt;            case EQUALS:&lt;br /&gt;                if (bits.size() &amp;gt; 0)&lt;br /&gt;                    patterns.add(new Pattern(startToken, toBitArray(bits), null));&lt;br /&gt;                return patterns;&lt;br /&gt;            case ZERO:&lt;br /&gt;                bits.add(false);&lt;br /&gt;                break;&lt;br /&gt;            case ONE:&lt;br /&gt;                bits.add(true);&lt;br /&gt;                break;&lt;br /&gt;            case DOT:&lt;br /&gt;            case NIL:&lt;br /&gt;            case SYMBOL:&lt;br /&gt;                patterns.add(new Pattern(startToken, toBitArray(bits), token));&lt;br /&gt;                bits.clear();&lt;br /&gt;                startToken = null;&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static boolean[] toBitArray(List&amp;lt;Boolean&amp;gt; list) {&lt;br /&gt;        boolean[] bits = new boolean[list.size()];&lt;br /&gt;        for (int i = 0; i &amp;lt; list.size(); i++)&lt;br /&gt;            bits[i] = list.get(i);&lt;br /&gt;        return bits;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public abstract class Expr {&lt;br /&gt;    private Token token;&lt;br /&gt;&lt;br /&gt;    protected Expr(Token token) {&lt;br /&gt;        this.token = token;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public abstract rt01_.val eval(rt01_.val[] bindings);&lt;br /&gt;&lt;br /&gt;    public Token getToken() {&lt;br /&gt;        return token;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class FuncallExpr extends Expr {&lt;br /&gt;    private Function function;&lt;br /&gt;    private Expr[] args;&lt;br /&gt;&lt;br /&gt;    public FuncallExpr(Token token, Function function, Expr[] args) {&lt;br /&gt;        super(token);&lt;br /&gt;        this.function = function;&lt;br /&gt;        this.args = args;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public rt01_.val eval(rt01_.val[] bindings) {&lt;br /&gt;        rt01_.val[] argVals = new rt01_.val[args.length];&lt;br /&gt;        for (int i = 0; i &amp;lt; argVals.length; i++)&lt;br /&gt;            argVals[i] = args[i].eval(bindings);&lt;br /&gt;        return function.eval(argVals);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Function getFunction() {&lt;br /&gt;        return function;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Expr[] getArgs() {&lt;br /&gt;        return args;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;import java.io.File;&lt;br /&gt;import java.io.PrintWriter;&lt;br /&gt;import java.util.HashSet;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;public class Function {&lt;br /&gt;    private Def[] defs;&lt;br /&gt;&lt;br /&gt;    public Function(Def[] defs) {&lt;br /&gt;        this.defs = defs;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getArity() {&lt;br /&gt;        return defs[0].getArity();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void parse(Map&amp;lt;String,Function&amp;gt; functions) {&lt;br /&gt;        for (Def def : defs)&lt;br /&gt;            def.parse(functions);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private class Result extends rt01_.function {&lt;br /&gt;        private rt01_.val[] args;&lt;br /&gt;        Result(rt01_.val[] args) {&lt;br /&gt;            this.args = args;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected rt01_.val eval() {&lt;br /&gt;            for (Def def : defs) {&lt;br /&gt;                rt01_.val val = def.eval(args);&lt;br /&gt;                if (val != null) {&lt;br /&gt;                    args = null; // let arguments get garbage collected&lt;br /&gt;                    return val;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            Token name = defs[defs.length-1].getName();&lt;br /&gt;            throw new RuntimeException(name.getLocation() + ": no matching pattern in definition of " + name.getSymbol());&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public rt01_.function eval(rt01_.val[] args) {&lt;br /&gt;        return new Result(args);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static final HashSet&amp;lt;String&amp;gt; reserved = new HashSet&amp;lt;String&amp;gt;();&lt;br /&gt;    static {&lt;br /&gt;        reserved.add("abstract");&lt;br /&gt;        reserved.add("assert");&lt;br /&gt;        reserved.add("boolean");&lt;br /&gt;        reserved.add("break");&lt;br /&gt;        reserved.add("byte");&lt;br /&gt;        reserved.add("case");&lt;br /&gt;        reserved.add("catch");&lt;br /&gt;        reserved.add("char");&lt;br /&gt;        reserved.add("class");&lt;br /&gt;        reserved.add("const");&lt;br /&gt;        reserved.add("continue");&lt;br /&gt;        reserved.add("default");&lt;br /&gt;        reserved.add("do");&lt;br /&gt;        reserved.add("double");&lt;br /&gt;        reserved.add("else");&lt;br /&gt;        reserved.add("enum");&lt;br /&gt;        reserved.add("extends");&lt;br /&gt;        reserved.add("false");&lt;br /&gt;        reserved.add("final");&lt;br /&gt;        reserved.add("finally");&lt;br /&gt;        reserved.add("float");&lt;br /&gt;        reserved.add("for");&lt;br /&gt;        reserved.add("goto");&lt;br /&gt;        reserved.add("if");&lt;br /&gt;        reserved.add("implements");&lt;br /&gt;        reserved.add("import");&lt;br /&gt;        reserved.add("instanceof");&lt;br /&gt;        reserved.add("int");&lt;br /&gt;        reserved.add("interface");&lt;br /&gt;        reserved.add("long");&lt;br /&gt;        reserved.add("native");&lt;br /&gt;        reserved.add("new");&lt;br /&gt;        reserved.add("null");&lt;br /&gt;        reserved.add("package");&lt;br /&gt;        reserved.add("private");&lt;br /&gt;        reserved.add("protected");&lt;br /&gt;        reserved.add("public");&lt;br /&gt;        reserved.add("return");&lt;br /&gt;        reserved.add("short");&lt;br /&gt;        reserved.add("static");&lt;br /&gt;        reserved.add("switch");&lt;br /&gt;        reserved.add("synchronized");&lt;br /&gt;        reserved.add("strictfp");&lt;br /&gt;        reserved.add("super");&lt;br /&gt;        reserved.add("this");&lt;br /&gt;        reserved.add("throw");&lt;br /&gt;        reserved.add("throws");&lt;br /&gt;        reserved.add("transient");&lt;br /&gt;        reserved.add("true");&lt;br /&gt;        reserved.add("try");&lt;br /&gt;        reserved.add("void");&lt;br /&gt;        reserved.add("volatile");&lt;br /&gt;        reserved.add("while");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static String mangle(String name) {&lt;br /&gt;        StringBuilder sb = new StringBuilder();&lt;br /&gt;        if (reserved.contains(name))&lt;br /&gt;            sb.append("__");&lt;br /&gt;        for (int i = 0; i &amp;lt; name.length(); i++)&lt;br /&gt;            switch (name.charAt(i)) {&lt;br /&gt;            case '0': case '1': case '2': case '3': case '4': case '5':&lt;br /&gt;            case '6': case '7': case '8': case '9':&lt;br /&gt;                if (i == 0)&lt;br /&gt;                    sb.append("__");&lt;br /&gt;            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':&lt;br /&gt;            case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':&lt;br /&gt;            case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':&lt;br /&gt;            case 's': case 't': case 'u': case 'v': case 'w': case 'x':&lt;br /&gt;            case 'y': case 'z':&lt;br /&gt;            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':&lt;br /&gt;            case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':&lt;br /&gt;            case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':&lt;br /&gt;            case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':&lt;br /&gt;            case 'Y': case 'Z':&lt;br /&gt;                sb.append(name.charAt(i));&lt;br /&gt;                break;&lt;br /&gt;            default:&lt;br /&gt;                sb.append('_').append(Integer.toHexString(name.charAt(i))).append('_');&lt;br /&gt;            }&lt;br /&gt;        return sb.toString();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getMangledName() {&lt;br /&gt;        return mangle(defs[0].getName().getSymbol());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void compile(PrintWriter out) throws Exception {&lt;br /&gt;        int arity = getArity();&lt;br /&gt;        String name = getMangledName();&lt;br /&gt;        out.print("public class ");&lt;br /&gt;        out.print(name);&lt;br /&gt;        out.println(" extends rt01_.function {");&lt;br /&gt;        for (int i = 0; i &amp;lt; arity; i++) {&lt;br /&gt;            out.print("    private rt01_.val a");&lt;br /&gt;            out.print(i);&lt;br /&gt;            out.println(";");&lt;br /&gt;        }&lt;br /&gt;        out.print("    public ");&lt;br /&gt;        out.print(name);&lt;br /&gt;        out.print("(");&lt;br /&gt;        for (int i = 0; i &amp;lt; arity; i++) {&lt;br /&gt;            if (i &amp;gt; 0)&lt;br /&gt;                out.print(",");&lt;br /&gt;            out.print("rt01_.val p");&lt;br /&gt;            out.print(i);&lt;br /&gt;        }&lt;br /&gt;        out.println(") {");&lt;br /&gt;        for (int i = 0; i &amp;lt; arity; i++) {&lt;br /&gt;            out.print("        a");&lt;br /&gt;            out.print(i);&lt;br /&gt;            out.print("=p");&lt;br /&gt;            out.print(i);&lt;br /&gt;            out.println(";");&lt;br /&gt;        }&lt;br /&gt;        out.println("    }");&lt;br /&gt;        out.println("    protected rt01_.val eval() {");&lt;br /&gt;        out.println("        rt01_.val val;");&lt;br /&gt;        out.print("        if (");&lt;br /&gt;        for (int i = 0; i &amp;lt; defs.length; i++) {&lt;br /&gt;            out.print("(val = m");&lt;br /&gt;            out.print(i);&lt;br /&gt;            out.print("()) == null &amp;amp;&amp;amp; ");&lt;br /&gt;        }&lt;br /&gt;        out.print("true) throw new RuntimeException(\"");&lt;br /&gt;        out.print(getLocation(defs[defs.length-1].getName()));&lt;br /&gt;        out.println(": pattern match failed\");");&lt;br /&gt;        for (int i = 0; i &amp;lt; arity; i++) {&lt;br /&gt;            out.print("        a");&lt;br /&gt;            out.print(i);&lt;br /&gt;            out.println(" = null;");&lt;br /&gt;        }&lt;br /&gt;        out.println("        return val;");&lt;br /&gt;        out.println("    }");&lt;br /&gt;        HashSet&amp;lt;String&amp;gt; constants = new HashSet&amp;lt;String&amp;gt;();&lt;br /&gt;        for (Def def : defs)&lt;br /&gt;            collectConstants(constants, def.getExpr());&lt;br /&gt;        for (String constant : constants) {&lt;br /&gt;            out.print("    private static final rt01_.val _");&lt;br /&gt;            out.print(constant);&lt;br /&gt;            if (constant.length() == 0) {&lt;br /&gt;                out.println(" = NIL;");&lt;br /&gt;            } else {&lt;br /&gt;                out.print(" = new rt01_.constant(\"");&lt;br /&gt;                out.print(constant);&lt;br /&gt;                out.println("\");");&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        for (int i = 0; i &amp;lt; defs.length; i++)&lt;br /&gt;            defs[i].compile(i, out);&lt;br /&gt;        out.println("    public static void main(String[] args) throws Exception {");&lt;br /&gt;        out.print("        main(args,");&lt;br /&gt;        out.print(arity);&lt;br /&gt;        out.print(",\"");&lt;br /&gt;        out.print(name);&lt;br /&gt;        out.println("\");");&lt;br /&gt;        out.println("    }");&lt;br /&gt;        out.println("}");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void collectConstants(HashSet&amp;lt;String&amp;gt; constants, Expr expr) {&lt;br /&gt;        if (expr instanceof ConstantExpr) {&lt;br /&gt;            constants.add(((ConstantExpr) expr).getBits());&lt;br /&gt;        } else if (expr instanceof ConcatExpr) {&lt;br /&gt;            collectConstants(constants, ((ConcatExpr) expr).getFirst());&lt;br /&gt;            collectConstants(constants, ((ConcatExpr) expr).getSecond());&lt;br /&gt;        } else if (expr instanceof FuncallExpr) {&lt;br /&gt;            for (Expr arg : ((FuncallExpr) expr).getArgs())&lt;br /&gt;                collectConstants(constants, arg);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static String getLocation(Token token) {&lt;br /&gt;        return new File(token.getFileName()).getName() + ":" + token.getLineNumber() + ":" + token.getColumn();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;import java.io.File;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;public class Interpreter {&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        Parser parser = new Parser();&lt;br /&gt;        int i;&lt;br /&gt;        String fname = null;&lt;br /&gt;        for (i = 0; i &amp;lt; args.length &amp;amp;&amp;amp; !args[i].equals("-"); i++) {&lt;br /&gt;            parser.add(args[i]);&lt;br /&gt;            fname = getFunction(args[i]);&lt;br /&gt;        }&lt;br /&gt;        if (i + 1 &amp;lt; args.length) {&lt;br /&gt;            fname = args[i+1];&lt;br /&gt;            i = i + 2;&lt;br /&gt;        }&lt;br /&gt;        boolean writeBits = false;&lt;br /&gt;        if (i &amp;lt; args.length &amp;amp;&amp;amp; "-bits".equals(args[i])) {&lt;br /&gt;            i++;&lt;br /&gt;            writeBits = true;&lt;br /&gt;        }&lt;br /&gt;        Function f = parser.getFunctions().get(fname);&lt;br /&gt;        if (writeBits)&lt;br /&gt;            rt01_.function.writeBits(f.eval(rt01_.function.args(args, f.getArity(), i)), System.out);&lt;br /&gt;        else&lt;br /&gt;            rt01_.function.write(f.eval(rt01_.function.args(args, f.getArity(), i)), System.out);&lt;br /&gt;        System.out.flush();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static String getFunction(String fileName) {&lt;br /&gt;        String fn = new File(fileName).getName();&lt;br /&gt;        if (fn.indexOf('.') &amp;gt; 0)&lt;br /&gt;            return fn.substring(0, fn.indexOf('.'));&lt;br /&gt;        else&lt;br /&gt;            return fn;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;import java.io.Reader;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.HashMap;&lt;br /&gt;import java.util.Iterator;&lt;br /&gt;import java.util.List;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;public class Parser {&lt;br /&gt;    private HashMap&amp;lt;String,Integer&amp;gt; arities = new HashMap&amp;lt;String,Integer&amp;gt;();&lt;br /&gt;    private HashMap&amp;lt;String,List&amp;lt;Def&amp;gt;&amp;gt; functions = new HashMap&amp;lt;String,List&amp;lt;Def&amp;gt;&amp;gt;();&lt;br /&gt;&lt;br /&gt;    public void add(String fileName) throws Exception {&lt;br /&gt;        add(new Tokenizer(fileName));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void add(Reader in, String fileName, int lineNumber, int column) {&lt;br /&gt;        add(new Tokenizer(in, fileName, lineNumber, column));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void add(Iterator&amp;lt;Token&amp;gt; tokenizer) {&lt;br /&gt;        addDefs(new DefReader(tokenizer));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void addDefs(Iterator&amp;lt;Def&amp;gt; defs) {&lt;br /&gt;        while (defs.hasNext()) {&lt;br /&gt;            Def def = defs.next();&lt;br /&gt;            Token name = def.getName();&lt;br /&gt;            if (arities.containsKey(name.getSymbol())) {&lt;br /&gt;                if (def.getArity() != arities.get(name.getSymbol()))&lt;br /&gt;                    throw new RuntimeException(name.getLocation() + ": arity mismatch in definition of " + name.getSymbol());&lt;br /&gt;            } else {&lt;br /&gt;                arities.put(name.getSymbol(), def.getArity());&lt;br /&gt;                functions.put(name.getSymbol(), new ArrayList&amp;lt;Def&amp;gt;());&lt;br /&gt;            }&lt;br /&gt;            functions.get(name.getSymbol()).add(def);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Map&amp;lt;String,Function&amp;gt; getFunctions() {&lt;br /&gt;        HashMap&amp;lt;String,Function&amp;gt; fns = new HashMap&amp;lt;String,Function&amp;gt;();&lt;br /&gt;        for (Map.Entry&amp;lt;String,List&amp;lt;Def&amp;gt;&amp;gt; entry : functions.entrySet()) {&lt;br /&gt;            List&amp;lt;Def&amp;gt; defs = entry.getValue();&lt;br /&gt;            fns.put(entry.getKey(), new Function(defs.toArray(new Def[defs.size()])));&lt;br /&gt;        }&lt;br /&gt;        for (Function function : fns.values())&lt;br /&gt;            function.parse(fns);&lt;br /&gt;        return fns;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Pattern {&lt;br /&gt;    private Token startToken;&lt;br /&gt;    private boolean[] bits;&lt;br /&gt;    private Token token;&lt;br /&gt;    private String fileName;&lt;br /&gt;    private int lineNumber;&lt;br /&gt;&lt;br /&gt;    public Pattern(Token startToken, boolean[] bits, Token token) {&lt;br /&gt;        this.startToken = startToken;&lt;br /&gt;        this.bits = bits;&lt;br /&gt;        this.token = token;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Token getStartToken() {&lt;br /&gt;        return startToken;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public boolean[] getBits() {&lt;br /&gt;        return bits;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Token getToken() {&lt;br /&gt;        return token;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public boolean isLiteral() {&lt;br /&gt;        return token == null || token.getType() == Token.Type.NIL;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public boolean isWild() {&lt;br /&gt;        return token != null &amp;amp;&amp;amp; token.getType() == Token.Type.DOT;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public boolean isBinding() {&lt;br /&gt;        return token != null &amp;amp;&amp;amp; token.getType() == Token.Type.SYMBOL;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public rt01_.val match(rt01_.val val) {&lt;br /&gt;        for (int i = 0; i &amp;lt; bits.length; i++) {&lt;br /&gt;            val = rt01_.val.trampoline(val);&lt;br /&gt;            if (val.nil() || val.head() != bits[i])&lt;br /&gt;                return null;&lt;br /&gt;            val = val.tail();&lt;br /&gt;        }&lt;br /&gt;        if (isLiteral()) {&lt;br /&gt;            val = rt01_.val.trampoline(val);&lt;br /&gt;            if (!val.nil())&lt;br /&gt;                return null;&lt;br /&gt;        }&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Token {&lt;br /&gt;    public enum Type {&lt;br /&gt;        ZERO, ONE, NIL, DOT, EQUALS, SYMBOL&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private Type type;&lt;br /&gt;    private String symbol;&lt;br /&gt;    private String fileName;&lt;br /&gt;    private int lineNumber;&lt;br /&gt;    private int column;&lt;br /&gt;&lt;br /&gt;    public Token(Type type, String symbol, String fileName, int lineNumber, int column) {&lt;br /&gt;        this.type = type;&lt;br /&gt;        this.symbol = symbol;&lt;br /&gt;        this.fileName = fileName;&lt;br /&gt;        this.lineNumber = lineNumber;&lt;br /&gt;        this.column = column;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Type getType() {&lt;br /&gt;        return type;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getSymbol() {&lt;br /&gt;        return symbol;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getFileName() {&lt;br /&gt;        return fileName;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getLineNumber() {&lt;br /&gt;        return lineNumber;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getColumn() {&lt;br /&gt;        return column;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getLocation() {&lt;br /&gt;        return fileName + ":" + lineNumber + ":" + column;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;import java.io.FileReader;&lt;br /&gt;import java.io.Reader;&lt;br /&gt;import java.util.Iterator;&lt;br /&gt;&lt;br /&gt;public class Tokenizer implements Iterator&amp;lt;Token&amp;gt; {&lt;br /&gt;    private Reader in;&lt;br /&gt;    private String fileName;&lt;br /&gt;    private int lineNumber;&lt;br /&gt;    private int column = 0;&lt;br /&gt;&lt;br /&gt;    private int pushback = -1;&lt;br /&gt;    private Token next;&lt;br /&gt;&lt;br /&gt;    public Tokenizer(String fileName) throws Exception {&lt;br /&gt;        this(new FileReader(fileName), fileName, 1, 0);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Tokenizer(Reader in, String fileName, int lineNumber, int column) {&lt;br /&gt;        this.in = in;&lt;br /&gt;        this.fileName = fileName;&lt;br /&gt;        this.lineNumber = lineNumber;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public boolean hasNext() {&lt;br /&gt;        if (next == null)&lt;br /&gt;            readNext();&lt;br /&gt;        return next != null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Token next() {&lt;br /&gt;        if (next == null)&lt;br /&gt;            readNext();&lt;br /&gt;        Token result =  next;&lt;br /&gt;        next = null;&lt;br /&gt;        return result;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void remove() {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void pushback(int lastChar) {&lt;br /&gt;        assert pushback &amp;lt; 0;&lt;br /&gt;        pushback = lastChar;&lt;br /&gt;        column--;&lt;br /&gt;        if (lastChar == '\n')&lt;br /&gt;            lineNumber--;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private int nextChar() {&lt;br /&gt;        int nextChar = -1;&lt;br /&gt;        if (pushback &amp;gt;= 0) {&lt;br /&gt;            nextChar = pushback;&lt;br /&gt;            pushback = -1;&lt;br /&gt;        } else {&lt;br /&gt;            try {&lt;br /&gt;                nextChar = in.read();&lt;br /&gt;            } catch (Exception e) {&lt;br /&gt;                throw new RuntimeException(e);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        if (nextChar &amp;gt;= 0) {&lt;br /&gt;            column++;&lt;br /&gt;            if (nextChar == '\n') {&lt;br /&gt;                lineNumber++;&lt;br /&gt;                column = 0;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return nextChar;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void readNext() {&lt;br /&gt;        for (;;) {&lt;br /&gt;            int nextChar = nextChar();&lt;br /&gt;            if (nextChar &amp;lt; 0)&lt;br /&gt;                return;&lt;br /&gt;            int saveLineNumber = lineNumber;&lt;br /&gt;            int saveColumn = column;&lt;br /&gt;            switch (nextChar) {&lt;br /&gt;            case '0':&lt;br /&gt;                next = new Token(Token.Type.ZERO, null, fileName, lineNumber, column);&lt;br /&gt;                return;&lt;br /&gt;            case '1':&lt;br /&gt;                next = new Token(Token.Type.ONE, null, fileName, lineNumber, column);&lt;br /&gt;                return;&lt;br /&gt;            case '_':&lt;br /&gt;                next = new Token(Token.Type.NIL, null, fileName, lineNumber, column);&lt;br /&gt;                return;&lt;br /&gt;            case '.':&lt;br /&gt;                next = new Token(Token.Type.DOT, null, fileName, lineNumber, column);&lt;br /&gt;                return;&lt;br /&gt;            case '=':&lt;br /&gt;                nextChar = nextChar();&lt;br /&gt;                if (nextChar != '=') {&lt;br /&gt;                    pushback(nextChar);&lt;br /&gt;                    next = new Token(Token.Type.EQUALS, null, fileName, saveLineNumber, saveColumn);&lt;br /&gt;                    return;&lt;br /&gt;                }&lt;br /&gt;                while (nextChar &amp;gt;= 0 &amp;amp;&amp;amp; nextChar != '\n')&lt;br /&gt;                    nextChar = nextChar();&lt;br /&gt;                continue;&lt;br /&gt;            case ' ': case '\t': case '\r': case '\n':&lt;br /&gt;                continue;&lt;br /&gt;            default:&lt;br /&gt;                StringBuilder sb = new StringBuilder();&lt;br /&gt;                sb.append((char) nextChar);&lt;br /&gt;                for (;;) {&lt;br /&gt;                    nextChar = nextChar();&lt;br /&gt;                    if (nextChar &amp;lt; 0) {&lt;br /&gt;                        next = new Token(Token.Type.SYMBOL, sb.toString(), fileName, saveLineNumber, saveColumn);&lt;br /&gt;                        return;&lt;br /&gt;                    }&lt;br /&gt;                    switch (nextChar) {&lt;br /&gt;                    case '0': case '1': case '_': case '.': case '=':&lt;br /&gt;                    case ' ': case '\t': case '\r': case '\n':&lt;br /&gt;                        pushback(nextChar);&lt;br /&gt;                        next = new Token(Token.Type.SYMBOL, sb.toString(), fileName, saveLineNumber, saveColumn);&lt;br /&gt;                        return;&lt;br /&gt;                    default:&lt;br /&gt;                        sb.append((char) nextChar);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here is 99 bottles of beer compiled to Java:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class __2 extends rt01_.function {&lt;br /&gt;    private rt01_.val a0;&lt;br /&gt;    public __2(rt01_.val p0) {&lt;br /&gt;        a0=p0;&lt;br /&gt;    }&lt;br /&gt;    protected rt01_.val eval() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        if ((val = m0()) == null &amp;amp;&amp;amp; true) throw new RuntimeException("99.01_:5:1: pattern match failed");&lt;br /&gt;        a0 = null;&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;    private static final rt01_.val _010 = new rt01_.constant("010");&lt;br /&gt;    private rt01_.val m0() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        a0 = trampoline(a0);&lt;br /&gt;        val = a0;&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || !val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || !val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        rt01_.val b0 = val;&lt;br /&gt;        return new rt01_.concat(_010,b0);&lt;br /&gt;    }&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        main(args,1,"__2");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public class __33r extends rt01_.function {&lt;br /&gt;    public __33r() {&lt;br /&gt;    }&lt;br /&gt;    protected rt01_.val eval() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        if ((val = m0()) == null &amp;amp;&amp;amp; true) throw new RuntimeException("99.01_:8:1: pattern match failed");&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;    private static final rt01_.val _001000000110111101101110001000000111010001101000011001010010000001110111011000010110110001101100 = new rt01_.constant("001000000110111101101110001000000111010001101000011001010010000001110111011000010110110001101100");&lt;br /&gt;    private rt01_.val m0() {&lt;br /&gt;        return _001000000110111101101110001000000111010001101000011001010010000001110111011000010110110001101100;&lt;br /&gt;    }&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        main(args,0,"__33r");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public class __4 extends rt01_.function {&lt;br /&gt;    private rt01_.val a0;&lt;br /&gt;    public __4(rt01_.val p0) {&lt;br /&gt;        a0=p0;&lt;br /&gt;    }&lt;br /&gt;    protected rt01_.val eval() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        if ((val = m0()) == null &amp;amp;&amp;amp; (val = m1()) == null &amp;amp;&amp;amp; (val = m2()) == null &amp;amp;&amp;amp; (val = m3()) == null &amp;amp;&amp;amp; true) throw new RuntimeException("99.01_:14:1: pattern match failed");&lt;br /&gt;        a0 = null;&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;    private static final rt01_.val _ = NIL;&lt;br /&gt;    private static final rt01_.val _1 = new rt01_.constant("1");&lt;br /&gt;    private static final rt01_.val _1001 = new rt01_.constant("1001");&lt;br /&gt;    private static final rt01_.val _0 = new rt01_.constant("0");&lt;br /&gt;    private rt01_.val m0() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        a0 = trampoline(a0);&lt;br /&gt;        val = a0;&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (!val.nil()) return null;&lt;br /&gt;        return _1001;&lt;br /&gt;    }&lt;br /&gt;    private rt01_.val m1() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        val = a0;&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (!val.nil()) return null;&lt;br /&gt;        return _;&lt;br /&gt;    }&lt;br /&gt;    private rt01_.val m2() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        a0 = trampoline(a0);&lt;br /&gt;        val = a0;&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        rt01_.val b0 = val;&lt;br /&gt;        return new rt01_.concat(_1,new __4(b0));&lt;br /&gt;    }&lt;br /&gt;    private rt01_.val m3() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        a0 = trampoline(a0);&lt;br /&gt;        val = a0;&lt;br /&gt;        if (val.nil() || !val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        rt01_.val b0 = val;&lt;br /&gt;        return new rt01_.concat(_0,b0);&lt;br /&gt;    }&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        main(args,1,"__4");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public class __5 extends rt01_.function {&lt;br /&gt;    private rt01_.val a0;&lt;br /&gt;    private rt01_.val a1;&lt;br /&gt;    public __5(rt01_.val p0,rt01_.val p1) {&lt;br /&gt;        a0=p0;&lt;br /&gt;        a1=p1;&lt;br /&gt;    }&lt;br /&gt;    protected rt01_.val eval() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        if ((val = m0()) == null &amp;amp;&amp;amp; (val = m1()) == null &amp;amp;&amp;amp; (val = m2()) == null &amp;amp;&amp;amp; (val = m3()) == null &amp;amp;&amp;amp; true) throw new RuntimeException("99.01_:20:1: pattern match failed");&lt;br /&gt;        a0 = null;&lt;br /&gt;        a1 = null;&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;    private static final rt01_.val _00110001 = new rt01_.constant("00110001");&lt;br /&gt;    private static final rt01_.val _01101110011011110010000001101101011011110111001001100101 = new rt01_.constant("01101110011011110010000001101101011011110111001001100101");&lt;br /&gt;    private static final rt01_.val _0011 = new rt01_.constant("0011");&lt;br /&gt;    private static final rt01_.val _01110011 = new rt01_.constant("01110011");&lt;br /&gt;    private rt01_.val m0() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        a0 = trampoline(a0);&lt;br /&gt;        val = a0;&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        a1 = trampoline(a1);&lt;br /&gt;        val = a1;&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (!val.nil()) return null;&lt;br /&gt;        return new rt01_.concat(_01101110011011110010000001101101011011110111001001100101,new rt01_.concat(new __7(),_01110011));&lt;br /&gt;    }&lt;br /&gt;    private rt01_.val m1() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        a0 = trampoline(a0);&lt;br /&gt;        val = a0;&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        a1 = trampoline(a1);&lt;br /&gt;        val = a1;&lt;br /&gt;        if (val.nil() || !val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (!val.nil()) return null;&lt;br /&gt;        return new rt01_.concat(_00110001,new __7());&lt;br /&gt;    }&lt;br /&gt;    private rt01_.val m2() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        a0 = trampoline(a0);&lt;br /&gt;        val = a0;&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = a1;&lt;br /&gt;        rt01_.val b0 = val;&lt;br /&gt;        return new rt01_.concat(_0011,new rt01_.concat(new __6(b0),new rt01_.concat(new __7(),_01110011)));&lt;br /&gt;    }&lt;br /&gt;    private rt01_.val m3() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        val = a0;&lt;br /&gt;        rt01_.val b0 = val;&lt;br /&gt;        val = a1;&lt;br /&gt;        rt01_.val b1 = val;&lt;br /&gt;        return new rt01_.concat(_0011,new rt01_.concat(new __6(b0),new rt01_.concat(_0011,new rt01_.concat(new __6(b1),new rt01_.concat(new __7(),_01110011)))));&lt;br /&gt;    }&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        main(args,2,"__5");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public class __6 extends rt01_.function {&lt;br /&gt;    private rt01_.val a0;&lt;br /&gt;    public __6(rt01_.val p0) {&lt;br /&gt;        a0=p0;&lt;br /&gt;    }&lt;br /&gt;    protected rt01_.val eval() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        if ((val = m0()) == null &amp;amp;&amp;amp; (val = m1()) == null &amp;amp;&amp;amp; (val = m2()) == null &amp;amp;&amp;amp; true) throw new RuntimeException("99.01_:25:1: pattern match failed");&lt;br /&gt;        a0 = null;&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;    private static final rt01_.val _ = NIL;&lt;br /&gt;    private static final rt01_.val _1 = new rt01_.constant("1");&lt;br /&gt;    private static final rt01_.val _0 = new rt01_.constant("0");&lt;br /&gt;    private rt01_.val m0() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        val = a0;&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (!val.nil()) return null;&lt;br /&gt;        return _;&lt;br /&gt;    }&lt;br /&gt;    private rt01_.val m1() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        a0 = trampoline(a0);&lt;br /&gt;        val = a0;&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        rt01_.val b0 = val;&lt;br /&gt;        return new rt01_.concat(new __6(b0),_0);&lt;br /&gt;    }&lt;br /&gt;    private rt01_.val m2() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        a0 = trampoline(a0);&lt;br /&gt;        val = a0;&lt;br /&gt;        if (val.nil() || !val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        rt01_.val b0 = val;&lt;br /&gt;        return new rt01_.concat(new __6(b0),_1);&lt;br /&gt;    }&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        main(args,1,"__6");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public class __7 extends rt01_.function {&lt;br /&gt;    public __7() {&lt;br /&gt;    }&lt;br /&gt;    protected rt01_.val eval() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        if ((val = m0()) == null &amp;amp;&amp;amp; true) throw new RuntimeException("99.01_:28:1: pattern match failed");&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;    private static final rt01_.val _00100000011000100110111101110100011101000110110001100101 = new rt01_.constant("00100000011000100110111101110100011101000110110001100101");&lt;br /&gt;    private rt01_.val m0() {&lt;br /&gt;        return _00100000011000100110111101110100011101000110110001100101;&lt;br /&gt;    }&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        main(args,0,"__7");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public class __8 extends rt01_.function {&lt;br /&gt;    private rt01_.val a0;&lt;br /&gt;    private rt01_.val a1;&lt;br /&gt;    public __8(rt01_.val p0,rt01_.val p1) {&lt;br /&gt;        a0=p0;&lt;br /&gt;        a1=p1;&lt;br /&gt;    }&lt;br /&gt;    protected rt01_.val eval() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        if ((val = m0()) == null &amp;amp;&amp;amp; (val = m1()) == null &amp;amp;&amp;amp; true) throw new RuntimeException("99.01_:32:1: pattern match failed");&lt;br /&gt;        a0 = null;&lt;br /&gt;        a1 = null;&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;    private rt01_.val m0() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        val = a0;&lt;br /&gt;        rt01_.val b0 = val;&lt;br /&gt;        a1 = trampoline(a1);&lt;br /&gt;        val = a1;&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (!val.nil()) return null;&lt;br /&gt;        return new __4(b0);&lt;br /&gt;    }&lt;br /&gt;    private rt01_.val m1() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        val = a0;&lt;br /&gt;        rt01_.val b0 = val;&lt;br /&gt;        val = a1;&lt;br /&gt;        return b0;&lt;br /&gt;    }&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        main(args,2,"__8");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public class __9 extends rt01_.function {&lt;br /&gt;    private rt01_.val a0;&lt;br /&gt;    private rt01_.val a1;&lt;br /&gt;    public __9(rt01_.val p0,rt01_.val p1) {&lt;br /&gt;        a0=p0;&lt;br /&gt;        a1=p1;&lt;br /&gt;    }&lt;br /&gt;    protected rt01_.val eval() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        if ((val = m0()) == null &amp;amp;&amp;amp; (val = m1()) == null &amp;amp;&amp;amp; true) throw new RuntimeException("99.01_:36:1: pattern match failed");&lt;br /&gt;        a0 = null;&lt;br /&gt;        a1 = null;&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;    private static final rt01_.val _1001 = new rt01_.constant("1001");&lt;br /&gt;    private static final rt01_.val _0010110000100000 = new rt01_.constant("0010110000100000");&lt;br /&gt;    private static final rt01_.val _001011100000101001010100011000010110101101100101001000000110111101101110011001010010000001100100011011110111011101101110001000000110000101101110011001000010000001110000011000010111001101110011001000000110100101110100001000000110000101110010011011110111010101101110011001000010110000100000 = new rt01_.constant("001011100000101001010100011000010110101101100101001000000110111101101110011001010010000001100100011011110111011101101110001000000110000101101110011001000010000001110000011000010111001101110011001000000110100101110100001000000110000101110010011011110111010101101110011001000010110000100000");&lt;br /&gt;    private static final rt01_.val _0010111000001010 = new rt01_.constant("0010111000001010");&lt;br /&gt;    private static final rt01_.val _0000 = new rt01_.constant("0000");&lt;br /&gt;    private static final rt01_.val _00101110000010100100011101101111001000000111010001101111001000000111010001101000011001010010000001110011011101000110111101110010011001010010000001100001011011100110010000100000011000100111010101111001001000000111001101101111011011010110010100100000011011010110111101110010011001010010110000100000 = new rt01_.constant("00101110000010100100011101101111001000000111010001101111001000000111010001101000011001010010000001110011011101000110111101110010011001010010000001100001011011100110010000100000011000100111010101111001001000000111001101101111011011010110010100100000011011010110111101110010011001010010110000100000");&lt;br /&gt;    private static final rt01_.val _001011100000101000001010 = new rt01_.constant("001011100000101000001010");&lt;br /&gt;    private rt01_.val m0() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        a0 = trampoline(a0);&lt;br /&gt;        val = a0;&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        a1 = trampoline(a1);&lt;br /&gt;        val = a1;&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (val.nil() || val.head()) return null;&lt;br /&gt;        val = val.tail();&lt;br /&gt;        val = trampoline(val);&lt;br /&gt;        if (!val.nil()) return null;&lt;br /&gt;        return new rt01_.concat(new __2(new __5(_0000,_0000)),new rt01_.concat(new b(),new rt01_.concat(new __33r(),new rt01_.concat(_0010110000100000,new rt01_.concat(new __5(_0000,_0000),new rt01_.concat(new b(),new rt01_.concat(_00101110000010100100011101101111001000000111010001101111001000000111010001101000011001010010000001110011011101000110111101110010011001010010000001100001011011100110010000100000011000100111010101111001001000000111001101101111011011010110010100100000011011010110111101110010011001010010110000100000,new rt01_.concat(new __5(_1001,_1001),new rt01_.concat(new b(),new rt01_.concat(new __33r(),_0010111000001010))))))))));&lt;br /&gt;    }&lt;br /&gt;    private rt01_.val m1() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        val = a0;&lt;br /&gt;        rt01_.val b0 = val;&lt;br /&gt;        val = a1;&lt;br /&gt;        rt01_.val b1 = val;&lt;br /&gt;        return new rt01_.concat(new __5(b0,b1),new rt01_.concat(new b(),new rt01_.concat(new __33r(),new rt01_.concat(_0010110000100000,new rt01_.concat(new __5(b0,b1),new rt01_.concat(new b(),new rt01_.concat(_001011100000101001010100011000010110101101100101001000000110111101101110011001010010000001100100011011110111011101101110001000000110000101101110011001000010000001110000011000010111001101110011001000000110100101110100001000000110000101110010011011110111010101101110011001000010110000100000,new rt01_.concat(new __5(new __8(b0,b1),new __4(b1)),new rt01_.concat(new b(),new rt01_.concat(new __33r(),new rt01_.concat(_001011100000101000001010,new __9(new __8(b0,b1),new __4(b1)))))))))))));&lt;br /&gt;    }&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        main(args,2,"__9");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public class __99 extends rt01_.function {&lt;br /&gt;    public __99() {&lt;br /&gt;    }&lt;br /&gt;    protected rt01_.val eval() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        if ((val = m0()) == null &amp;amp;&amp;amp; true) throw new RuntimeException("99.01_:38:1: pattern match failed");&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;    private static final rt01_.val _1001 = new rt01_.constant("1001");&lt;br /&gt;    private rt01_.val m0() {&lt;br /&gt;        return new __9(_1001,_1001);&lt;br /&gt;    }&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        main(args,0,"__99");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;public class b extends rt01_.function {&lt;br /&gt;    public b() {&lt;br /&gt;    }&lt;br /&gt;    protected rt01_.val eval() {&lt;br /&gt;        rt01_.val val;&lt;br /&gt;        if ((val = m0()) == null &amp;amp;&amp;amp; true) throw new RuntimeException("99.01_:2:1: pattern match failed");&lt;br /&gt;        return val;&lt;br /&gt;    }&lt;br /&gt;    private static final rt01_.val _0010000001101111011001100010000001100010011001010110010101110010 = new rt01_.constant("0010000001101111011001100010000001100010011001010110010101110010");&lt;br /&gt;    private rt01_.val m0() {&lt;br /&gt;        return _0010000001101111011001100010000001100010011001010110010101110010;&lt;br /&gt;    }&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        main(args,0,"b");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-8379102795345813132?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/8379102795345813132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/02/i-had-idea-of-making-compiler-for-01.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8379102795345813132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/8379102795345813132'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/02/i-had-idea-of-making-compiler-for-01.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-2166709932928070239</id><published>2010-02-01T00:00:00.001-08:00</published><updated>2010-02-01T00:00:10.390-08:00</updated><title type='text'></title><content type='html'>Here is a &lt;a href="/2009/12/parenthesis-hell-programming-language.html"&gt;Parenthesis Hell&lt;/a&gt; interpreter in Java.  It uses a mutable trie for the letrec bindings, where the interpreter in Haskell uses an immutable trie.  Also, phi.Value.iterator() is a bit more complicated than the Haskell equivalent, which would be&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;data Flattened = HEAD | TAIL&lt;br /&gt;&lt;br /&gt;flattened :: Value -&gt; [Flattened]&lt;br /&gt;flattened Nil = []&lt;br /&gt;flattened (Cons head tail) = HEAD : flattened head ++ TAIL : flattened tail&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I originally wrote the interpreter as multiple classes, but contained all of them as nested classes in a single class for this post.  Some of the code would have been more straightforward had it been written recursively, but then larger data would cause stack overflows.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import java.io.EOFException;&lt;br /&gt;import java.io.FileReader;&lt;br /&gt;import java.io.InputStream;&lt;br /&gt;import java.io.InputStreamReader;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;import java.io.OutputStream;&lt;br /&gt;import java.io.Reader;&lt;br /&gt;import java.util.EnumMap;&lt;br /&gt;import java.util.Iterator;&lt;br /&gt;import java.util.LinkedList;&lt;br /&gt;&lt;br /&gt;public class phi {&lt;br /&gt;    public static class EnumTrie&amp;lt;K extends Enum&amp;lt;K&amp;gt;,V&amp;gt; {&lt;br /&gt;        private EnumMap&amp;lt;K,EnumTrie&amp;lt;K,V&amp;gt;&amp;gt; map;&lt;br /&gt;        private V value = null;&lt;br /&gt;&lt;br /&gt;        public EnumTrie(Class&amp;lt;K&amp;gt; keyType) {&lt;br /&gt;            map = new EnumMap&amp;lt;K,EnumTrie&amp;lt;K,V&amp;gt;&amp;gt;(keyType);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private EnumTrie(EnumTrie&amp;lt;K,V&amp;gt; trie) {&lt;br /&gt;            map = new EnumMap&amp;lt;K,EnumTrie&amp;lt;K,V&amp;gt;&amp;gt;(trie.map);&lt;br /&gt;            map.clear();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public V getValue() {&lt;br /&gt;            return value;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public EnumTrie&amp;lt;K,V&amp;gt; getSubtrie(K k) {&lt;br /&gt;            return map.get(k);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public EnumTrie&amp;lt;K,V&amp;gt; findPrefix(Iterator&amp;lt;K&amp;gt; iterator) {&lt;br /&gt;            EnumTrie&amp;lt;K,V&amp;gt; trie = this;&lt;br /&gt;            while (trie != null &amp;amp;&amp;amp; iterator.hasNext())&lt;br /&gt;                trie = trie.map.get(iterator.next());&lt;br /&gt;            return trie;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public V get(Iterable&amp;lt;K&amp;gt; key) {&lt;br /&gt;            EnumTrie&amp;lt;K,V&amp;gt; trie = findPrefix(key.iterator());&lt;br /&gt;            return trie != null ? trie.value : null;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private EnumTrie&amp;lt;K,V&amp;gt; addPrefix(Iterator&amp;lt;K&amp;gt; iterator) {&lt;br /&gt;            EnumTrie&amp;lt;K,V&amp;gt; trie = this;&lt;br /&gt;            while (iterator.hasNext()) {&lt;br /&gt;                K k = iterator.next();&lt;br /&gt;                EnumTrie&amp;lt;K,V&amp;gt; subtrie = trie.map.get(k);&lt;br /&gt;                if (subtrie == null) {&lt;br /&gt;                    subtrie = new EnumTrie&amp;lt;K,V&amp;gt;(trie);&lt;br /&gt;                    trie.map.put(k, subtrie);&lt;br /&gt;                }&lt;br /&gt;                trie = subtrie;&lt;br /&gt;            }&lt;br /&gt;            return trie;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public V put(Iterable&amp;lt;K&amp;gt; key, V value) {&lt;br /&gt;            EnumTrie&amp;lt;K,V&amp;gt; trie;&lt;br /&gt;            if (value != null) {&lt;br /&gt;                trie = addPrefix(key.iterator());&lt;br /&gt;            } else {&lt;br /&gt;                trie = findPrefix(key.iterator());&lt;br /&gt;                if (trie == null)&lt;br /&gt;                    return null;&lt;br /&gt;            }&lt;br /&gt;            trie.value = value;&lt;br /&gt;            return value;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static abstract class Value implements Iterable&amp;lt;Value.Flattened&amp;gt; {&lt;br /&gt;        public enum Flattened { HEAD, TAIL }&lt;br /&gt;&lt;br /&gt;        public static final Value NIL = new NilValue();&lt;br /&gt;&lt;br /&gt;        public boolean isNil() {&lt;br /&gt;            return false;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public abstract Value getHead();&lt;br /&gt;        public abstract Value getTail();&lt;br /&gt;&lt;br /&gt;        public static Value read(Reader reader) throws IOException {&lt;br /&gt;            LinkedList&amp;lt;Value&amp;gt; stack = new LinkedList&amp;lt;Value&amp;gt;();&lt;br /&gt;            LinkedList&amp;lt;Boolean&amp;gt; open = new LinkedList&amp;lt;Boolean&amp;gt;();&lt;br /&gt;            for (;;) {&lt;br /&gt;                int c = reader.read();&lt;br /&gt;                if (c &amp;lt; 0) {&lt;br /&gt;                    throw new EOFException();&lt;br /&gt;                } else if (c == '(') {&lt;br /&gt;                    open.push(true);&lt;br /&gt;                } else if (c == ')') {&lt;br /&gt;                    if (open.size() == 0)&lt;br /&gt;                        throw new EOFException();&lt;br /&gt;                    if (open.pop()) {&lt;br /&gt;                        if (open.size() == 0)&lt;br /&gt;                            return NIL;&lt;br /&gt;                        open.push(false);&lt;br /&gt;                        stack.push(NIL);&lt;br /&gt;                    } else {&lt;br /&gt;                        Value value = new Pair(stack.pop(), NIL);&lt;br /&gt;                        while (!open.pop())&lt;br /&gt;                            value = new Pair(stack.pop(), value);&lt;br /&gt;                        if (open.size() == 0)&lt;br /&gt;                            return value;&lt;br /&gt;                        stack.push(value);&lt;br /&gt;                        open.push(false);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public String toString() {&lt;br /&gt;            StringBuilder sb = new StringBuilder();&lt;br /&gt;            sb.append('(');&lt;br /&gt;            toString(sb);&lt;br /&gt;            sb.append(')');&lt;br /&gt;            return sb.toString();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void toString(StringBuilder sb) {&lt;br /&gt;            if (!isNil()) {&lt;br /&gt;                sb.append('(');&lt;br /&gt;                getHead().toString(sb);&lt;br /&gt;                sb.append(')');&lt;br /&gt;                getTail().toString(sb);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Iterator&amp;lt;Flattened&amp;gt; iterator() {&lt;br /&gt;            final LinkedList&amp;lt;Value&amp;gt; stack = new LinkedList&amp;lt;Value&amp;gt;();&lt;br /&gt;            return new Iterator&amp;lt;Flattened&amp;gt;() {&lt;br /&gt;                private Value value = Value.this;&lt;br /&gt;&lt;br /&gt;                public boolean hasNext() {&lt;br /&gt;                    return !value.isNil() || stack.size() &amp;gt; 0;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                public Flattened next() {&lt;br /&gt;                    if (value.isNil()) {&lt;br /&gt;                        value = stack.pop().getTail();&lt;br /&gt;                        return Flattened.TAIL;&lt;br /&gt;                    } else {&lt;br /&gt;                        stack.push(value);&lt;br /&gt;                        value = value.getHead();&lt;br /&gt;                        return Flattened.HEAD;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                public void remove() {&lt;br /&gt;                    throw new UnsupportedOperationException();&lt;br /&gt;                }&lt;br /&gt;            };&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static class NilValue extends Value {&lt;br /&gt;            public boolean isNil() {&lt;br /&gt;                return true;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public Value getHead() {&lt;br /&gt;                return NilValue.this;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public Value getTail() {&lt;br /&gt;                return NilValue.this;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static class Pair extends Value {&lt;br /&gt;            private Value head;&lt;br /&gt;            private Value tail;&lt;br /&gt;&lt;br /&gt;            public Pair(Value head, Value tail) {&lt;br /&gt;                this.head = head;&lt;br /&gt;                this.tail = tail;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public Value getHead() {&lt;br /&gt;                return head;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public Value getTail() {&lt;br /&gt;                return tail;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static void write(Value value, OutputStream out) throws IOException {&lt;br /&gt;            int bit = 128;&lt;br /&gt;            int b = 0;&lt;br /&gt;            while (!value.isNil()) {&lt;br /&gt;                Value head = value.getHead();&lt;br /&gt;                if (head.isNil()) {&lt;br /&gt;                    value = value.getTail();&lt;br /&gt;                } else {&lt;br /&gt;                    b |= bit;&lt;br /&gt;                    value = head;&lt;br /&gt;                }&lt;br /&gt;                if (bit == 1) {&lt;br /&gt;                    out.write(b);&lt;br /&gt;                    bit = 128;&lt;br /&gt;                    b = 0;&lt;br /&gt;                } else {&lt;br /&gt;                    bit &amp;gt;&amp;gt;= 1;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static class InputValue extends Value {&lt;br /&gt;            private InputStream in;&lt;br /&gt;            private int bit;&lt;br /&gt;            private int b;&lt;br /&gt;            private Value head = null;&lt;br /&gt;            private Value tail = null;&lt;br /&gt;&lt;br /&gt;            public InputValue(InputStream in) {&lt;br /&gt;                this(in, 128, 0);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            private InputValue(InputStream in, int bit, int b) {&lt;br /&gt;                this.in = in;&lt;br /&gt;                this.bit = bit;&lt;br /&gt;                this.b = b;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            private void init() {&lt;br /&gt;                if (head == null) {&lt;br /&gt;                    head = Value.NIL;&lt;br /&gt;                    tail = Value.NIL;&lt;br /&gt;                    if (bit == 0) {&lt;br /&gt;                        try {&lt;br /&gt;                            b = in.read();&lt;br /&gt;                        } catch (IOException e) {&lt;br /&gt;                            b = -1;&lt;br /&gt;                        }&lt;br /&gt;                        if (b &amp;lt; 0)&lt;br /&gt;                            return;&lt;br /&gt;                        bit = 128;&lt;br /&gt;                    }&lt;br /&gt;                    if ((b &amp;amp; bit) != 0)&lt;br /&gt;                        head = new InputValue(in, bit&amp;gt;&amp;gt;1, b);&lt;br /&gt;                    else&lt;br /&gt;                        tail = new InputValue(in, bit&amp;gt;&amp;gt;1, b);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public Value getHead() {&lt;br /&gt;                init();&lt;br /&gt;                return head;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public Value getTail() {&lt;br /&gt;                init();&lt;br /&gt;                return tail;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class Scope {&lt;br /&gt;        private Scope outer;&lt;br /&gt;        private EnumTrie&amp;lt;Value.Flattened,Interp.Op&amp;gt; bindings;&lt;br /&gt;        private Value arg;&lt;br /&gt;&lt;br /&gt;        public Scope(Scope outer, EnumTrie&amp;lt;Value.Flattened,Interp.Op&amp;gt; bindings, Value arg) {&lt;br /&gt;            this.outer = outer;&lt;br /&gt;            this.bindings = bindings;&lt;br /&gt;            this.arg = arg;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Value getArg() {&lt;br /&gt;            Scope scope = this;&lt;br /&gt;            while (scope.arg == null)&lt;br /&gt;                scope = scope.outer;&lt;br /&gt;            return scope.arg;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Interp.Op getBinding(Value name) {&lt;br /&gt;            Scope scope = this;&lt;br /&gt;            while (scope != null) {&lt;br /&gt;                if (scope.bindings != null) {&lt;br /&gt;                    Interp.Op op = scope.bindings.get(name);&lt;br /&gt;                    if (op != null)&lt;br /&gt;                        return op;&lt;br /&gt;                }&lt;br /&gt;                scope = scope.outer;&lt;br /&gt;            }&lt;br /&gt;            return null;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static class Interp {&lt;br /&gt;        private Scope rootScope;&lt;br /&gt;&lt;br /&gt;        public Interp(Value input) {&lt;br /&gt;            rootScope = new Scope(null, rootBindings(), input);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public Value eval(Value expr) {&lt;br /&gt;            return eval(expr, rootScope);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected Value eval(final Value expr, final Scope scope) {&lt;br /&gt;            if (expr.isNil())&lt;br /&gt;                return scope.getArg();&lt;br /&gt;            return new LazyValue() {&lt;br /&gt;                protected Value getValue() {&lt;br /&gt;                    return scope.getBinding(expr.getHead()).op(expr.getTail(), scope);&lt;br /&gt;                }&lt;br /&gt;            };&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public interface Op {&lt;br /&gt;            public Value op(Value expr, Scope scope);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private EnumTrie&amp;lt;Value.Flattened,Interp.Op&amp;gt; rootBindings() {&lt;br /&gt;            Value E3 = Value.NIL;&lt;br /&gt;            Value EE33 = new Value.Pair(E3,E3);&lt;br /&gt;            Value EE3E33 = new Value.Pair(E3,EE33);&lt;br /&gt;            Value EE3E3E33 = new Value.Pair(E3,EE3E33);&lt;br /&gt;            Value EEE333 = new Value.Pair(EE33,E3);&lt;br /&gt;            Value EEE33E33 = new Value.Pair(EE33,EE33);&lt;br /&gt;            Value EEEE3333 = new Value.Pair(EEE333,E3);&lt;br /&gt;            Value EE3EE333 = new Value.Pair(E3,EEE333);&lt;br /&gt;            EnumTrie&amp;lt;Value.Flattened,Interp.Op&amp;gt; rootBindings = new EnumTrie&amp;lt;Value.Flattened,Interp.Op&amp;gt;(Value.Flattened.class);&lt;br /&gt;            rootBindings.put(E3, new QuoteOp());&lt;br /&gt;            rootBindings.put(EE33, new LetOp());&lt;br /&gt;            rootBindings.put(EE3E33, new CdrOp());&lt;br /&gt;            rootBindings.put(EE3E3E33, new IfOp());&lt;br /&gt;            rootBindings.put(EEE333, new CarOp());&lt;br /&gt;            rootBindings.put(EEE33E33, new ConsOp());&lt;br /&gt;            rootBindings.put(EEEE3333, new EvalOp());&lt;br /&gt;            rootBindings.put(EE3EE333, new ConcatOp());&lt;br /&gt;            return rootBindings;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private class QuoteOp implements Op {&lt;br /&gt;            public Value op(Value arg, Scope scope) {&lt;br /&gt;                return arg;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt; &lt;br /&gt;        private class LetOp implements Op {&lt;br /&gt;            public Value op(Value arg, Scope scope) {&lt;br /&gt;                EnumTrie&amp;lt;Value.Flattened,Interp.Op&amp;gt; bindings = new EnumTrie&amp;lt;Value.Flattened,Interp.Op&amp;gt;(Value.Flattened.class);&lt;br /&gt;                Scope letScope = new Scope(scope, bindings, null);&lt;br /&gt;                Value bindingList = arg.getHead();&lt;br /&gt;                while (!bindingList.isNil()) {&lt;br /&gt;                    Value binding = bindingList.getHead();&lt;br /&gt;                    bindingList = bindingList.getTail();&lt;br /&gt;                    bindings.put(binding.getHead(), new DefinedOp(binding.getTail(), letScope));&lt;br /&gt;                }&lt;br /&gt;                return eval(arg.getTail(), letScope);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private class DefinedOp implements Op {&lt;br /&gt;            private Value body;&lt;br /&gt;            private Scope letScope;&lt;br /&gt;&lt;br /&gt;            public DefinedOp(Value body, Scope letScope) {&lt;br /&gt;                this.body = body;&lt;br /&gt;                this.letScope = letScope;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public Value op(final Value arg, final Scope scope) {&lt;br /&gt;                return eval(body, new Scope(letScope, null, eval(arg, scope)));&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private class CdrOp implements Op {&lt;br /&gt;            public Value op(Value arg, Scope scope) {&lt;br /&gt;                return eval(arg, scope).getTail();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt; &lt;br /&gt;        private class IfOp implements Op {&lt;br /&gt;            public Value op(Value arg, Scope scope) {&lt;br /&gt;                if (arg.isNil())&lt;br /&gt;                    return Value.NIL;&lt;br /&gt;                Value body = arg.getTail();&lt;br /&gt;                if (body.isNil())&lt;br /&gt;                    return Value.NIL;&lt;br /&gt;                if (eval(arg.getHead(), scope).isNil())&lt;br /&gt;                    return eval(body.getTail(), scope);&lt;br /&gt;                else&lt;br /&gt;                    return eval(body.getHead(), scope);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt; &lt;br /&gt;        private class CarOp implements Op {&lt;br /&gt;            public Value op(Value arg, Scope scope) {&lt;br /&gt;                return eval(arg, scope).getHead();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt; &lt;br /&gt;        private class ConsOp implements Op {&lt;br /&gt;            public Value op(Value arg, Scope scope) {&lt;br /&gt;                if (arg.isNil())&lt;br /&gt;                    return Value.NIL;&lt;br /&gt;                return new Value.Pair(eval(arg.getHead(), scope), eval(arg.getTail(), scope));&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt; &lt;br /&gt;        private class EvalOp implements Op {&lt;br /&gt;            public Value op(Value arg, Scope scope) {&lt;br /&gt;                return eval(eval(arg, scope), scope);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt; &lt;br /&gt;        private class ConcatOp implements Op {&lt;br /&gt;            public Value op(Value arg, Scope scope) {&lt;br /&gt;                if (arg.isNil())&lt;br /&gt;                    return Value.NIL;&lt;br /&gt;                Value value = eval(arg.getHead(), scope);&lt;br /&gt;                Value rest = eval(arg.getTail(), scope);&lt;br /&gt;                LinkedList&amp;lt;Boolean&amp;gt; stack = new LinkedList&amp;lt;Boolean&amp;gt;();&lt;br /&gt;                LinkedList&amp;lt;Value&amp;gt; tails = new LinkedList&amp;lt;Value&amp;gt;();&lt;br /&gt;                for (;;) {&lt;br /&gt;                    if (value.isNil())&lt;br /&gt;                        break;&lt;br /&gt;                    Value head = value.getHead();&lt;br /&gt;                    Value tail = value.getTail();&lt;br /&gt;                    if (head.isNil()) {&lt;br /&gt;                        if (tail.isNil())&lt;br /&gt;                            break;&lt;br /&gt;                        stack.push(false);&lt;br /&gt;                        value = tail;&lt;br /&gt;                    } else {&lt;br /&gt;                        stack.push(true);&lt;br /&gt;                        tails.push(tail);&lt;br /&gt;                        value = head;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                while (!stack.isEmpty()) {&lt;br /&gt;                    if (stack.pop())&lt;br /&gt;                        rest = new Value.Pair(rest, tails.pop());&lt;br /&gt;                    else&lt;br /&gt;                        rest = new Value.Pair(Value.NIL, rest);&lt;br /&gt;                }&lt;br /&gt;                return rest;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private abstract class LazyValue extends Value {&lt;br /&gt;            private Value value = null;&lt;br /&gt;            protected abstract Value getValue();&lt;br /&gt;            public boolean isNil() {&lt;br /&gt;                if (value == null)&lt;br /&gt;                    value = getValue();&lt;br /&gt;                return value.isNil();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public Value getHead() {&lt;br /&gt;                if (value == null)&lt;br /&gt;                    value = getValue();&lt;br /&gt;                return value.getHead();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public Value getTail() {&lt;br /&gt;                if (value == null)&lt;br /&gt;                    value = getValue();&lt;br /&gt;                return value.getTail();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        Value expr;&lt;br /&gt;        Value input;&lt;br /&gt;        if (args.length == 0) {&lt;br /&gt;            expr = Value.read(new InputStreamReader(System.in));&lt;br /&gt;            input = Value.NIL;&lt;br /&gt;        } else {&lt;br /&gt;            expr = Value.read(new FileReader(args[0]));&lt;br /&gt;            input = new Value.InputValue(System.in);&lt;br /&gt;        }&lt;br /&gt;        Value.write(new Interp(input).eval(expr), System.out);&lt;br /&gt;        System.out.flush();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-2166709932928070239?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/2166709932928070239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/02/here-is-parenthesis-hell-interpreter-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2166709932928070239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/2166709932928070239'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/02/here-is-parenthesis-hell-interpreter-in.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-3819639807280634013</id><published>2010-01-25T00:00:00.000-08:00</published><updated>2010-01-25T00:00:07.343-08:00</updated><title type='text'></title><content type='html'>I got pulled into optimizing some ancient C code.  This was pre-ANSI C.  This first thing I found was that there was floating-point function being called repeatedly in some loops with identical arguments, so I added some code near the top of the file that was something like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;static float floating_point_function_table[20];&lt;br /&gt;static int floating_point_function_table_initialized = 0;&lt;br /&gt;&lt;br /&gt;static void init_floating_point_function_table()&lt;br /&gt;{&lt;br /&gt;    int i;&lt;br /&gt;    if (floating_point_function_table_initialized)&lt;br /&gt;        return;&lt;br /&gt;    for (i = 0; i &lt; 20; i++)&lt;br /&gt;        floating_point_function_table[i] = floating_point_function((float) i);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;When I tried it out, it was a lot faster.  After replacing the function_point_function() calls with the table lookups, the loops, which did some other stuff as well, ran in about one sixth the time.  But the results were garbage.  And I was baffled for at least an hour.  The function looked something like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;float floating_point_function(arg)&lt;br /&gt;  float arg;&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Since this was ancient code, it was implicitly declared to return int when it was being called in init_floating_point_function_table(), so I moved init_floating_point_function_table() below the definition of floating_point_function(), and it worked.&lt;br /&gt;&lt;br /&gt;I also discovered a bunch of loops like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    for (i = 0; i &lt; SOME_CONSTANT/SOME_CONSTANT_ARRAY[some_parameter]; i++) ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;in code that stood out when profiling, and declared a new int variable at the top of the function:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    int SOME_CONSTANT_OVER_SOME_CONSTANT_ARRAY_some_parameter;&lt;br /&gt;   SOME_CONSTANT_OVER_SOME_CONSTANT_ARRAY_some_parameter = SOME_CONSTANT/SOME_CONSTANT_ARRAY[some_parameter];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and changed the loops to:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    for (i = 0; i &lt; SOME_CONSTANT_OVER_SOME_CONSTANT_ARRAY_some_parameter; i++) ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;and, surprisingly, even when compiled with full optimization, this change caused this section of code to run in less than half the time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-3819639807280634013?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/3819639807280634013/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/01/i-got-pulled-into-optimizing-some.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3819639807280634013'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/3819639807280634013'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/01/i-got-pulled-into-optimizing-some.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-4235923915173549966</id><published>2010-01-18T00:00:00.000-08:00</published><updated>2010-01-18T00:00:05.450-08:00</updated><title type='text'></title><content type='html'>Here is 99 bottles of beer in &lt;a href="/2009/12/parenthesis-hell-programming-language.html"&gt;Parenthesis Hell&lt;/a&gt;.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;((())((((())(()))(()()())(((())))((()()())(((()))((())))(((())()&lt;br /&gt;)(((())(()))((())())(((()))((())))(()()))(()())((())))(()()())((&lt;br /&gt;()())((())))(((())())(())((())(()))((())())((()())((())))(()()))&lt;br /&gt;(()()))(()()))((()((()()(()()()((()(()()(()((()()(((()((()(()()(&lt;br /&gt;()(((()(()()())))))))))))))))))))))(()()())()((()()())(((())))((&lt;br /&gt;()()())(((()))((())))((()()())(((()))((()))((())))((()()())(((()&lt;br /&gt;))((()))((()))((())))((()()())(((()))((()))((()))((()))((())))((&lt;br /&gt;()()())(((()))((()))((()))((()))((()))((())))((()()())(((()))(((&lt;br /&gt;)))((()))((()))((()))((()))((())))((()()())(((()))((()))((()))((&lt;br /&gt;()))((()))((()))((()))((())))(()()()(((()()(())))))()()()(((()()&lt;br /&gt;()()))))()()()((()(((()))))))()()()((()((()())))))()()()((()(()(&lt;br /&gt;())))))()()()((()(()()()))))()()()((()()((())))))()()()((()()(()&lt;br /&gt;()))))()()()((()()()(()))))()()()((()()()()())))((()((()()()((()&lt;br /&gt;((()((((()(((()(()(()((()(((()()(((()(()()()))))))))))))))))))))&lt;br /&gt;)))))(()()())(((())))(((())(()))((())())((()((()()(()()()((()(()&lt;br /&gt;()(()((()()(((()((()(()()(()(((()(()()())))))))))))))))))))))(((&lt;br /&gt;))))(()((()()(()()()((()(()()(()((()()(((()((()(()()(()(((()(()(&lt;br /&gt;)())))))))))))))))))))))(()()))(()()())((()()))((()((()()(()()()&lt;br /&gt;((()(()()(()((()()(((()((()(()()(()(((()(()()())))))))))))))))))&lt;br /&gt;))))(()()))()()((()(((()()((()((((()()(()()()()()()((()((()(()((&lt;br /&gt;()((((()(((()()(()()((()()(()(()))))))))))))))))))))))))))))))))&lt;br /&gt;((()(()()()()((()((()((((()(((()(()(()((()(((()()(((()(()()())))&lt;br /&gt;)))))))))))))))))))))(()()())(((())))(((())(()))((())())((()((()&lt;br /&gt;()(()()()((()(()()(()((()()(((()((()(()()(()(((()(()()()))))))))&lt;br /&gt;)))))))))))))((())))(()((()()(()()()((()(()()(()((()()(((()((()(&lt;br /&gt;()()(()(((()(()()())))))))))))))))))))))(()()))(()()())((()()))(&lt;br /&gt;(()((()()(()()()((()(()()(()((()()(((()((()(()()(()(((()(()()())&lt;br /&gt;))))))))))))))))))))(()()))()()(()()(((()()((()((((()()(()()()()&lt;br /&gt;()()((()((()(()((()((((()(((()()(()()((()()(()(())))))))))))))))&lt;br /&gt;))))))))))))))))((()(((()()((()))))))(()()())(((())))(()()(((()(&lt;br /&gt;)((()))))))(()()())((()()))((()()())(((()))(()()))(()()(((()()((&lt;br /&gt;()))))))()())()()(((()()((()))))))((()((()()()(()()((()((((()(((&lt;br /&gt;()(()()()(((()(()()()((()((()()()((()()(()(()(((()()((()))))))))&lt;br /&gt;)))))))))))))))))))))))((())(()))((())())((()((()()()((()((()(((&lt;br /&gt;(()(((()(()(()((()(((()()(((()(()()()))))))))))))))))))))))))))(&lt;br /&gt;(())(()))((())())(()()()(()()()()()()((()()()(()()((()((((()((((&lt;br /&gt;)(()()()(((()(()()()((()((()()()((()()(()(()))))))))))))))))))))&lt;br /&gt;)))))))((())(()))((())())((()(((()()((())))))))()()()(()()()()()&lt;br /&gt;()((()((((()((()()((()()()(()()()()()()((()()()(()()((()()(()(()&lt;br /&gt;((()()(()(()(((()()(()()))))))))))))))))))))))))))))((()(()()()(&lt;br /&gt;)(()()((()((((()(((()(()()()(((()(()()()((()((()()()((()()(()(()&lt;br /&gt;(((()()((()))))))))))))))))))))))))))))))((())(()))((())())((()(&lt;br /&gt;()()()()((()((()((((()(((()(()(()((()(((()()(((()(()()()))))))))&lt;br /&gt;)))))))))))))))))((())(()))((())())(()()()(()()()()()()((()()()(&lt;br /&gt;()()((()((((()(((()(()()()(((()(()()()((()((()()()((()()(()(()))&lt;br /&gt;)))))))))))))))))))))))))((())(()))((())())((()(((()()((()))))))&lt;br /&gt;)()()()(()()()()()()((()((((()((()()((()()()(()()()()()()((()()(&lt;br /&gt;)(()()((()()(()(()((()()(()(()(((()()(()()))))))))))))))))))))))&lt;br /&gt;))))))((()((()()(()()()((()()(()(()((()()()((()))))))))))))(()()&lt;br /&gt;())((()()))(((())())(((())))((()))(()()))((())())(((()))((())))(&lt;br /&gt;)((((((((())))))))))((()(((()((()()()((()()()(())))))))))((())((&lt;br /&gt;)))((())())((()(()()()()(()()((()((((()(((()(()()()(((()(()()()(&lt;br /&gt;(()((()()()((()()(()(()(((()()((()))))))))))))))))))))))))))))))&lt;br /&gt;)((())(()))((())())(()()()(()()()()()()((()((((()((()(((()()()((&lt;br /&gt;)()()()()()(((()(()()()((()(()()()()((()()(()(()()(()()()()()()(&lt;br /&gt;((()(((()((()()()()(()((()((()()()((()((()()()()(()((()()()()(()&lt;br /&gt;()()()()())))))))))))))))))))))))))))))))))))))))))))))))((())((&lt;br /&gt;)))((())())((()((()()()(()()((()((((()(((()(()()()(((()(()()()((&lt;br /&gt;()((()()()((()()(()(()(((()()((())))))))))))))))))))))))))))))))&lt;br /&gt;)(()()())(((())))((()(((()((()()()((()()(()())))))))))(()((()()(&lt;br /&gt;()()()((()()(()(()((()()()((())))))))))))))(()()())((()()))((()(&lt;br /&gt;((()((()()()((()()(()())))))))))(()((()()(()()()((()()(()(()((()&lt;br /&gt;()()((())))))))))))))()()()(()(((()()()()()(()(()()(()()()(((()(&lt;br /&gt;(()((((()()(()()()()()()(((()(()()()((()((((()()(()()()()()()(((&lt;br /&gt;()(()()()((()(()()()()((()()(()(()()(()()()()()()(((()()((()((((&lt;br /&gt;)(()()()((()((((()(((()()(()()((()()(()(()()(()()()()()()((()()(&lt;br /&gt;)()(()((()(((()()((()()(()()()()(()()()()()()((()()()(()()(((()(&lt;br /&gt;()(()((((()()(()()(()()()()()()(((()()((()((()((((()((()((()(()(&lt;br /&gt;(()()(()(()()(()()()()()()((()((()(()((()((((()(((()()(()()((()(&lt;br /&gt;)(()(()()(()((()()()()(()()()()()()()(((()()(()()(((()()(()()(()&lt;br /&gt;()()()()()((()()()(()()((()((((()(((()(()()()(((()(()()()((()(((&lt;br /&gt;)()()((()()(()(()(((()()((()()(()()()()()()((()((((()((()()((()(&lt;br /&gt;)()(()()()()()()((()()()(()()((()()(()(()((()()(()(()(((()()(()(&lt;br /&gt;)()(()()()()()()((()((((()((()(((()()()(()()()()()()(((()(()()()&lt;br /&gt;((()(()()()()((()()(()(()()(()()()()()()(((()(((()((()()()()(()(&lt;br /&gt;(()((()()()((()((()()()()(()(((()()()()()(()(()())))))))))))))))&lt;br /&gt;))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;))))))))))))))))))))))))))))))))))))))))))((()(((()((()()()((()(&lt;br /&gt;)(()())))))))))((())(()))((())())(()()()(()(((()()()()()(()(()()&lt;br /&gt;(()(()(()()()((()()()()(()((()(()((()((()()(()(()()(()()()()()()&lt;br /&gt;((()((((()((()(((()()((()()(()(()()(()()()()()()((()()(()()()(((&lt;br /&gt;)((((()(((()(((()((()(((()()()(()()()()()()((()()()()(()((()((((&lt;br /&gt;)()((()()(()()()()(()()()()()()(((()()()()()((()()()()(()(((()()&lt;br /&gt;((()(((()()((()()(()()()()()()((()(()()(()(((()(()()()()(()()()(&lt;br /&gt;)()()((()()()()(()(((()()(()()((()((((()(((()(()(()((()(((()()((&lt;br /&gt;()()(()()()()(()((()()()()(()()()()()())))))))))))))))))))))))))&lt;br /&gt;))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&lt;br /&gt;)))))))))))))))))))))))))))))))))))))))((())(()))((())())((()(((&lt;br /&gt;)()()(()()((()((((()(((()(()()()(((()(()()()((()((()()()((()()((&lt;br /&gt;)(()(((()()((()))))))))))))))))))))))))))))))))()()()(()()()()()&lt;br /&gt;()((()((((()((()(((()()()(()()()()()()(((()(()()()((()(()()()()(&lt;br /&gt;(()()(()(()()(()()()()()()(((()(((()((()()()()(()((()((()()()(((&lt;br /&gt;)((()()()()(()(((()()()()()(()(()()()()()(()(()())))))))))))))))&lt;br /&gt;))))))))))))))))))))))))))))))))))))((()(((()((()()))))))((())((&lt;br /&gt;)))((())())((()(((()((()()()((()()()(()))))))))))(()()())(((()))&lt;br /&gt;)((()(((()((()()))))))(()((()()(()()()((()()(()(()((()()()((()))&lt;br /&gt;)))))))))))(()()())((()()))((()(((()((()()))))))(()((()()(()()()&lt;br /&gt;((()()(()(()((()()()((())))))))))))))()))(()(((()((()()))))))()(&lt;br /&gt;((((((((())))))))))((((((((())))))))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I did not actually write the preceding code.  I actually wrote what follows, which looks much more Lisp-like, and ran it through a preprocessor that did symbol and string substitutions.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(((arg   . ())&lt;br /&gt;  (quote . ())&lt;br /&gt;  (let   . (()))&lt;br /&gt;  (cdr   . (()()))&lt;br /&gt;  (if    . (()()()))&lt;br /&gt;  (car   . ((())))&lt;br /&gt;  (cons  . ((())()))&lt;br /&gt;  (eval  . (((()))))&lt;br /&gt;  (concat  . ((())(()))))&lt;br /&gt; .&lt;br /&gt; (let ((concat&lt;br /&gt; . (if (car . arg)&lt;br /&gt;       (if (car car . arg)&lt;br /&gt;    (cons (concat cons (car car . arg) . (cdr . arg))&lt;br /&gt;   . (cdr car . arg))&lt;br /&gt;  . (if (cdr car . arg)&lt;br /&gt;        (cons (quote . ())&lt;br /&gt;       . (concat cons (cdr car . arg) . (cdr . arg)))&lt;br /&gt;      . (cdr . arg)))&lt;br /&gt;     . (cdr . arg)))&lt;br /&gt;       ("digit" . &lt;br /&gt; (if arg&lt;br /&gt;     (if (car . arg)&lt;br /&gt;  (if (car car . arg)&lt;br /&gt;      (if (car car car . arg)&lt;br /&gt;   (if (car car car car . arg)&lt;br /&gt;       (if (car car car car car . arg)&lt;br /&gt;    (if (car car car car car car . arg)&lt;br /&gt;        (if (car car car car car car car . arg)&lt;br /&gt;     (if (car car car car car car car car . arg)&lt;br /&gt;         (quote . "9")&lt;br /&gt;       . (quote . "8"))&lt;br /&gt;          . (quote . "7"))&lt;br /&gt;      . (quote . "6"))&lt;br /&gt;         . (quote . "5"))&lt;br /&gt;     . (quote . "4"))&lt;br /&gt;        . (quote . "3"))&lt;br /&gt;    . (quote . "2"))&lt;br /&gt;       . (quote . "1"))&lt;br /&gt;   . (quote . "0")))&lt;br /&gt;       ("count" .&lt;br /&gt; (if (car . arg)&lt;br /&gt;     (concat cons ("digit" car . arg) . ("digit" cdr . arg))&lt;br /&gt;   . (if (cdr . arg)&lt;br /&gt;  ("digit" cdr . arg)&lt;br /&gt;       . (quote . "no more"))))&lt;br /&gt;       ("Count" .&lt;br /&gt; (if (car . arg)&lt;br /&gt;     (concat cons ("digit" car . arg) . ("digit" cdr . arg))&lt;br /&gt;   . (if (cdr . arg)&lt;br /&gt;  ("digit" cdr . arg)&lt;br /&gt;       . (quote . "No more"))))&lt;br /&gt;       ("s" .&lt;br /&gt; (if (car . arg)&lt;br /&gt;     (quote . "s")&lt;br /&gt;   . (if (cdr . arg)&lt;br /&gt;  (if (car cdr . arg)&lt;br /&gt;      (quote . "s")&lt;br /&gt;    . (quote . ""))&lt;br /&gt;       . (quote . "s"))))&lt;br /&gt;       ("bottles" .&lt;br /&gt; (concat cons ("count" . arg) .&lt;br /&gt;  (concat cons (quote . " bottle") .&lt;br /&gt;   (concat cons ("s" . arg) . (quote . " of beer")))))&lt;br /&gt;       ("Bottles" .&lt;br /&gt; (concat cons ("Count" . arg) .&lt;br /&gt;  (concat cons (quote . " bottle") .&lt;br /&gt;   (concat cons ("s" . arg) . (quote . " of beer")))))&lt;br /&gt;       ("dec" .&lt;br /&gt; (if (cdr . arg)&lt;br /&gt;     (cons (car . arg) . (car cdr . arg))&lt;br /&gt;   . (cons (car car . arg) . (quote . (((((((((())))))))))))))&lt;br /&gt;       ("v1" .&lt;br /&gt; (concat cons ("Bottles" . arg)&lt;br /&gt;  concat cons (quote . " on the wall, ")&lt;br /&gt;  concat cons ("bottles" . arg) .&lt;br /&gt;  (if (car . arg)&lt;br /&gt;      ("v2" "dec" . arg)&lt;br /&gt;    . (if (cdr . arg)&lt;br /&gt;   ("v2" "dec" . arg)&lt;br /&gt;        . (quote . ".&lt;br /&gt;Go to the store and buy some more, 99 bottles of beer on the wall.&lt;br /&gt;")))))&lt;br /&gt;       ("v2" .&lt;br /&gt; (concat cons (quote . ".&lt;br /&gt;Take one down and pass it around, ")&lt;br /&gt;  concat cons ("bottles" . arg)&lt;br /&gt;  . (quote . " on the wall.&lt;br /&gt;&lt;br /&gt;")))&lt;br /&gt;       ("v" .&lt;br /&gt; (concat cons ("v1" . arg)&lt;br /&gt;  . (if (car . arg)&lt;br /&gt;        ("v" "dec" . arg)&lt;br /&gt;      . (if (cdr . arg)&lt;br /&gt;     ("v" "dec" . arg)&lt;br /&gt;   . (quote . ()))))))&lt;br /&gt;   . ("v" quote . ((((((((((()))))))))) . (((((((((())))))))))))))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1029341293641516198-4235923915173549966?l=iwritethecode.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://iwritethecode.blogspot.com/feeds/4235923915173549966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://iwritethecode.blogspot.com/2010/01/here-is-99-bottles-of-beer-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/4235923915173549966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1029341293641516198/posts/default/4235923915173549966'/><link rel='alternate' type='text/html' href='http://iwritethecode.blogspot.com/2010/01/here-is-99-bottles-of-beer-in.html' title=''/><author><name>Q. P. Liu</name><uri>http://www.blogger.com/profile/02682443075316110578</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1029341293641516198.post-215803360960180588</id><published>2010-01-11T00:00:00.000-08:00</published><updated>2010-01-11T00:00:01.924-08:00</updated><title type='text'></title><content type='html'>After load testing, the caching optimization still had performance issues, so a synchronized HashMap.get got turned into an unsynchronized HashMap.get.&lt;br /&gt;&lt;br /&gt;The code becomes something like&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;for (;;) {&lt;br /&gt;    Object entry = null;&lt;br /&gt;    // cache is a jdk1.4 HashMap, so if there is a concurrent modification,&lt;br /&gt;    // the worst can happen is either an erroneous null is returned or an&lt;br /&gt;    // ArrayIndexOutOfBoundsException is thrown.  This HashMap.get is not&lt;br /&gt;    // synchronized for performance reasons, as revealed in load tests.&lt;br /&gt;    //&lt;br /&gt;    // In general, a concurrent modification could result a HashMap.get&lt;br /&gt;    // to return a (very recently) stale value, but that is not a concern&lt;br /&gt;    // in this case, since the only stale value could be an expired lock&lt;br /&gt;    // object, which will result in retrying the HashMap.get.&lt;br /&gt;    //&lt;br /&gt;    // The ArrayIndexOutOfBoundsException is not likely to ever be thrown,&lt;br /&gt;    // but the HashMap.remove in the finally block could theoretically&lt;br /&gt;    // cause it.  The catch block causes the ArrayIndexOutOfBoundsException&lt;br /&gt;    // to be the same as a potentially erroneous null.&lt;br /&gt;    // &lt;br /&gt;    // The erroneous null is not a problem, because if null is returned,&lt;br /&gt;    // because the subsequent HashMap.get is synchronized.&lt;br /&gt;    try {&lt;br /&gt;        entry = cache.get(key);&lt;br /&gt;    } catch (ArrayIndexOutOfBoundsException e) {&lt;br /&gt;    }&lt;br /&gt;    if (entry == null) {&lt;br /&gt;        Object lock = new Object();&lt
