<?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-22374588</id><updated>2011-10-24T21:08:18.974+02:00</updated><category term='amiga'/><category term='lisp'/><category term='code'/><category term='c++'/><category term='rant'/><title type='text'>voodoo slide</title><subtitle type='html'>Nu åker vi</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-22374588.post-3793008752085884585</id><published>2010-08-31T14:55:00.002+02:00</published><updated>2010-08-31T14:59:04.542+02:00</updated><title type='text'>Tundra, my build system</title><content type='html'>I've been working on a build system, Tundra, to scratch my own itches and it's come along far enough that I've released the code in beta form over at github (&lt;a href="http://github.com/deplinenoise/tundra"&gt;http://github.com/deplinenoise/tundra&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
Tundra has taken on many different architectures over the years I've hacked on it, but I've finally arrived at a Lua frontend and a C backend. Here are some of the goals I've had with Tundra:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Optimize for iterative builds&lt;/li&gt;
&lt;li&gt;Flexible configuration frontend (easy to add configurations and variants)&lt;/li&gt;
&lt;li&gt;Keep the build system core small and simple&lt;/li&gt;
&lt;li&gt;Utilize multi-core hardware even for scanning and up-to-date checks&lt;/li&gt;
&lt;li&gt;Reliably support code generation (passes, DAG scheduling)&lt;/li&gt;
&lt;li&gt;Separate configuration and building to make it easier to optimize &amp;amp; debug&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Of course now that Tundra is nearing completion it's fun to show some performance numbers. Noel Llopis did a great writeup on the various build systems available a few years back&amp;nbsp;(&lt;a href="http://gamesfromwithin.com/the-quest-for-the-perfect-build-system"&gt;http://gamesfromwithin.com/the-quest-for-the-perfect-build-system&lt;/a&gt;). Using his script to generate 10 libraries with 50 files each (500 files total) I ran a small benchmark.&amp;nbsp;Here's the statistics output from a no-act run of Tundra on that dataset. This was on a Core i7 box running Win7/64 with everything in disk cache; but the disk itself is a slow 7200 RPM disk:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;J:\Scratch\benchmark&amp;gt;tundra --debug-stats
*** build success, 0 jobs run
post-build stats:
  files tracked: 1511 (1511 directly from DAG), file table load 1.64%
  relations tracked: 1034, table load 1.12%
  relation cache load: 0.003s save: 0.000s
  nodes with ancestry: 513 of 513 possible
  time spent in Lua doing setup: 0.057s
    - time spent iterating directories (glob): 0.004s over 10 calls
  total time spent in build loop: 0.032s
    - implicit dependency scanning: 0.152s
    - output directory creation/mgmt: 0.000s
    - command execution: 0.000s
    - (parallel) stat() time: 0.039s (2010 calls out of 0 queries)
    - (parallel) file signing time: 0.031s (md5: 0, timestamp: 1500)
    - up2date checks time: 0.016s
  efficiency: 0.00%
total time spent in tundra: 0.0926s&lt;/pre&gt;&lt;br /&gt;
I'd say 93 ms for a no-act build is pretty nice considering that this includes full #include scanning! We can see that 57 ms was spent in Lua code creating the input DAG and 32 ms was spent in the native build loop. This is nice because if the build master is complaining about slow builds we can easily see if it's due to his bad scripting or due to actual build performance ;)&lt;br /&gt;
&lt;br /&gt;
If you want to give Tundra a spin (it's beta quality software) you can get a binary drop and the documentation here:&amp;nbsp;&lt;a href="http://github.com/deplinenoise/tundra/downloads"&gt;http://github.com/deplinenoise/tundra/downloads&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-3793008752085884585?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/3793008752085884585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=3793008752085884585' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/3793008752085884585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/3793008752085884585'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2010/08/tundra-my-build-system.html' title='Tundra, my build system'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-1506129984411470055</id><published>2010-07-23T11:25:00.000+02:00</published><updated>2010-07-23T11:25:44.070+02:00</updated><title type='text'>Visual Studio and your AppData\Temp directory</title><content type='html'>Visual Studio has a tendency to leave a lot of junk files behind when you cancel builds. A colleague of mine at DICE had 22,000 temp files&amp;nbsp;weighing in at over&amp;nbsp;14.5 GB in his AppData\Temp directory! Having more than a few hundered files in a single directory on NTFS is suicide, so you can imagine how much his compile times improved when he emptied that directory.&lt;br /&gt;
&lt;br /&gt;
The real question is how to get Microsoft's CL to stop creating these temporary files, and failing that, how to make it clean them up when you abort it?&lt;br /&gt;
&lt;br /&gt;
In the meantime, I'm relying on a little tool I have running on a schedule that wipes files that are older than a few days from my AppData\Temp directory. Lo-fi solution to a yucky problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-1506129984411470055?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/1506129984411470055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=1506129984411470055' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/1506129984411470055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/1506129984411470055'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2010/07/visual-studio-and-your-appdatatemp.html' title='Visual Studio and your AppData\Temp directory'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-5752873060486635427</id><published>2010-06-08T10:25:00.001+02:00</published><updated>2010-06-08T10:26:35.419+02:00</updated><title type='text'>How to stop Vista from trashing your disk</title><content type='html'>Ever notice how Vista churns your HDD? I had the misfortune of having to install Vista on a machine again and finally took the time to figure out what to do to make it stop. I knew about the first four, but the last two were new to me and made all the difference:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Disable ReadyBoost&lt;/li&gt;
&lt;li&gt;Disable SuperFetch&lt;/li&gt;
&lt;li&gt;Disable the Windows Search service&lt;/li&gt;
&lt;li&gt;Disable the scheduled Disk Defragmentation task&lt;/li&gt;
&lt;li&gt;Disable the scheduled System Restore task (shows up as super-high System Volume Information traffic)&lt;/li&gt;
&lt;li&gt;Go into the registry and &lt;a href="http://www.technipages.com/vista-enabledisable-superfetch.html"&gt;disable prefetching entirely&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;All these steps removes 99% of the extra disk activity and now the disk doesn't rattle all the time :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-5752873060486635427?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/5752873060486635427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=5752873060486635427' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/5752873060486635427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/5752873060486635427'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2010/06/how-to-stop-vista-from-trashing-your.html' title='How to stop Vista from trashing your disk'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-5948035839507289633</id><published>2010-02-03T23:53:00.002+01:00</published><updated>2010-09-14T20:08:44.883+02:00</updated><title type='text'>c-amplify prototype available</title><content type='html'>I've uploaded the c-amplify to gitorious so people can look at the code. It's pretty rough around the edges right now (it's a rant-fueled hack after all), but here's a basic guide to getting started: &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Clone the repository here: &lt;a href="http://github.com/deplinenoise/c-amplify"&gt;http://github.com/deplinenoise/c-amplify &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Get the excellent &lt;a href="http://common-lisp.net/project/cl-match/doc/clmatch.htm"&gt;cl-match&lt;/a&gt; library and add it to your central ASDF registry&lt;/li&gt;
&lt;li&gt;Load the c-amplify ASDF system into your lisp (Clozure and SBCL on Win32 should work well, it's what I'm using)&lt;/li&gt;
&lt;li&gt;In the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;:se.defmacro.c-amplify&lt;/span&gt; package, evaluate this from the REPL:&lt;/li&gt;

&lt;ul&gt;&lt;li style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;(load-csys-file #p"test-input/test.csys")&lt;/li&gt;
&lt;li style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;(update-system (find-system :core))&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;You should now have an amplified core.c file that you can examine (and eventually compile, once a lot of quirks have been worked out in c-amplify itself) :)&lt;/li&gt;
&lt;/ul&gt;As always, feel free to leave your comments.&lt;span id="goog_1580378565"&gt;&lt;/span&gt;&lt;span id="goog_1580378566"&gt;&lt;/span&gt;&lt;a href="http://www.blogger.com/"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-5948035839507289633?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/5948035839507289633/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=5948035839507289633' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/5948035839507289633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/5948035839507289633'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2010/02/c-amplify-prototype-available.html' title='c-amplify prototype available'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-1030759976264022429</id><published>2010-01-22T17:26:00.009+01:00</published><updated>2010-01-26T09:59:13.803+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>Amplifying C</title><content type='html'>&lt;h2&gt;&lt;a name="_on_c"&gt;&lt;/a&gt;On C++&lt;/h2&gt;
&lt;p&gt;Having programmed in C++ professionally for well over 10 years I have
learned all of it. I have all the books, I know all the tricks. And I
don&amp;#8217;t like it anymore.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Update: This intro apparently made some people see red, because "no man could possibly know all of C++". If that includes you, you can read it as: "I've shipped 4 AAA games on MLOC code bases, and here's my take on the C++ abstractions you can reasonably use in projects that big".
&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Basically game teams using C++ fall into the same trap every time:
they try to create abstractions with whatever is in the C++ toolbox
and they fail miserably. On the next project they&amp;#8217;re a little bit
smarter from the experience so they set out to fix their abstractions
and create new ones. And fail.&lt;/p&gt;
&lt;p&gt;Quickly going over the major abstraction mechanisms C++ introduced
over C I&amp;#8217;m arguing that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
Templates suck as they cause link-time spam and compile times to
  skyrocket. They severely bloat the size of the debug symbol file,
  which on large projects can easily reach several hundred megabytes
  of data. Abstractions built with templates perform differently
  depending on whether compiler optimizations are enabled or not
  (every tried debugging Boost code?). They&amp;#8217;re essentially unusable on
  large code bases beyond container-of-T and simple functions.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
RTTI sucks because it doesn&amp;#8217;t do what anyone wants, and you can&amp;#8217;t
  even rely on it returning a type name formatted in a certain way.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Classes suck because their guts have to be in headers for all to see.
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All these high-level concepts are flawed and you can&amp;#8217;t alter their
semantics because they&amp;#8217;re set in ISO stone. What all teams do then is
to reinvent all the language components that don&amp;#8217;t work for them, and
sets up rules forbidding the use of the other features. Every C++ shop
has its own "accepted" subset.&lt;/p&gt;
&lt;p&gt;Basically the C++ game developer community is slowly navigating away
from C++'s abstraction patterns. We left operator overloading mostly
in the 90&amp;#8217;s (some vector libraries still use it). We ditched RTTI back
in 2001. Exceptions are firmly off as they don&amp;#8217;t even work on all
platforms we develop for. A lot of people are advocating that we stop
using member functions to reduce coupling.&lt;/p&gt;
&lt;p&gt;This may sound harsh, but to me these are clear signs that C++ isn&amp;#8217;t
providing any real cost benefit for us, and that we should be writing
code in other ways.&lt;/p&gt;
&lt;h2&gt;&lt;a name="_coding_c"&gt;&lt;/a&gt;Coding C&lt;/h2&gt;
&lt;p&gt;Many C++ game programmers have started to turn towards C (or C-like
C++) to get away from the flaws of C++. Targeting C manually with
larger systems can be a lot of work, because it offers very basic
abstraction facilities. There are functions, enums, tagged types
(structs and unions) and a rudimentary type system, but that&amp;#8217;s about
it.&lt;/p&gt;
&lt;p&gt;But let&amp;#8217;s look at C as a platform for a minute. C is lean, compiles
super fast, it&amp;#8217;s supported everywhere and all the tools we need to
ship games such as compilers and debuggers (including the obscure and
proprietary) work well with it. If you need platform-specific
intrinsics to get on with your job, you can rely on the target
platform&amp;#8217;s C compiler to provide them.&lt;/p&gt;
&lt;p&gt;As C is such a simple, predictable language that works everywhere it
makes a lot of sense to generate C code. Indeed many projects have
done so, but typically the meat of the application has still been
written in plain C as code generation is typically used for language
interfaces or parser generators.&lt;/p&gt;
&lt;h2&gt;&lt;a name="_the_lisp_way"&gt;&lt;/a&gt;The Lisp Way&lt;/h2&gt;
&lt;p&gt;Having also programmed a lot of Common Lisp over the years, I&amp;#8217;ve seen
how the Lisp family of languages deals with extensibility. In Lisp,
you write your own abstractions that become a part of the project&amp;#8217;s
language. This remarkable feature is enabled basically through two
simple things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
Programs can be treated as data (because they can be thought of as
  parse trees)
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
There are macros which transform such data (that is, your programs)
  into other programs (implementing the abstractions).
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#8217;m going to suggest something mildly radical: we should prefer C over
C++. But not straight-up C. We should create our own C with the
abstractions we need, built right into the language, customized for
the problems we&amp;#8217;re working on.&lt;/p&gt;
&lt;h2&gt;&lt;a name="_amplification"&gt;&lt;/a&gt;Amplification&lt;/h2&gt;
&lt;p&gt;We can apply many of the ideas that make Lisp powerful to C if we drop
its Algol-like syntax. What is the difference between the following
two program fragments?&lt;/p&gt;
&lt;table border="0" bgcolor="#e8e8e8" width="100%" cellpadding="10"&gt;&lt;tr&gt;&lt;td&gt;
&lt;pre&gt;int my_function(int a, int b) {
    return a + b;
}&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;table border="0" bgcolor="#e8e8e8" width="100%" cellpadding="10"&gt;&lt;tr&gt;&lt;td&gt;
&lt;pre&gt;(defun my-function ((a int) (b int) (return int))
  (return (+ a b))&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;Answer: none, they are equivalent as far as semantics go. The latter
can trivially be parsed (using very simple rules) and transformed into
the former, and so it is still the same C program. This is good news,
because Lisp has shown us that if we represent programs as data, we
can transform that data arbitrarily before evaluating or compiling it.&lt;/p&gt;
&lt;p&gt;In my prototype system, c-amplify, I&amp;#8217;m doing exactly this. The system
introduces an "amplification" phase where s-expressions are
transformed to C code before a traditional build system runs.&lt;/p&gt;
&lt;p&gt;The c-amplify system has the following major parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
A system definition facility (specifying input files and
  dependencies)
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
A reader, parsing ca source files
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
A persistent function and type database which is updated as source
  files are amplified.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
A pretty-printing C code generator&amp;#8201;&amp;#8212;&amp;#8201;important as we&amp;#8217;re going to be
  debugging the generated code.
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The system is intended to be run incrementally as source files are
changed, re-reading changed files, updating the database and writing
generated output. A traditional build system can then be used to the
resulting files.&lt;/p&gt;
&lt;p&gt;The persistent database is an interesting component that isn&amp;#8217;t
strictly needed for the system but enables a lot of neat features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
Type inference. Because all functions and types are known, c-amplify
  can easily supply a type-of operator for arbitrary expressions. This
  can be used as the basis for type inferring macros similar to auto in
  C++0x or var in C#.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Hook functions could be installed that run over the database and do
  additional work. For example, instrumenting all writes to a
  particular struct field, generating reflection info or performing
  project-specific checks on how types or functions are used. The
  possibilities are pretty much endless. Remember all those times
  you&amp;#8217;ve thought: if we could only access this thing in the compiler
  we could give an error message if the code does this thing? Well,
  with hooks you could.
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a name="_raii_uncluttered"&gt;&lt;/a&gt;RAII, uncluttered&lt;/h2&gt;
&lt;p&gt;Let&amp;#8217;s look at one such macro that solves a real problem: making sure a
file handle is closed in an orderly manner, even when there are
multiple exit points from the block.&lt;/p&gt;
&lt;p&gt;In situations like this, C++ fans can&amp;#8217;t wait to tell you about
RAII. RAII means creating a stack object of some utility type that
performs resource cleanup in its destructor. If we look at the
&lt;tt&gt;AutoFile&lt;/tt&gt; type we need to type up to implement RAII we find that
exactly one line is providing the abstraction we need (the
destructor), the rest is boilerplate:&lt;/p&gt;
&lt;table border="0" bgcolor="#e8e8e8" width="100%" cellpadding="10"&gt;&lt;tr&gt;&lt;td&gt;
&lt;pre&gt;class AutoFile // auxillary type
{
  private:
    FILE* f;

  public:
    AutoFile(const char* fn, const char* mode) {
      f = fopen(fn, mode);
    }
    ~AutoFile() { if (f) fclose(f); }
    operator FILE*() { return f; }

  private:
    AutoFile(const AutoFile&amp;amp;);
    AutoFile&amp;amp; operator=(const AutoFile&amp;amp;);
};

// later, that same day..
{
   AutoFile file("c:/temp/foo.txt", "w");
   fprintf(file, "Hello, world");
}&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;What Lisp programmers do to manage resources is to create
block-wrapping macros (usually starting with the word &lt;tt&gt;with-&lt;/tt&gt;). The
macros sits around a body of code, indicating visually that the code
wrapped by the macro will have access to some resource. The macro
expansion is guaranteed to clean up the resource regardless of how the
block terminates. Here&amp;#8217;s an example of using such a macro with
c-amplify:&lt;/p&gt;
&lt;table border="0" bgcolor="#e8e8e8" width="100%" cellpadding="10"&gt;&lt;tr&gt;&lt;td&gt;
&lt;pre&gt;(with-open-file (f "c:/temp/foo.txt" "w")
  (fprintf f "Hello, world"))&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;If we ask c-amplify to macro-expand this we see that the details of
calling &lt;tt&gt;fopen&lt;/tt&gt; and &lt;tt&gt;fclose&lt;/tt&gt; are being handled as if we had written
out everything by hand:&lt;/p&gt;
&lt;table border="0" bgcolor="#e8e8e8" width="100%" cellpadding="10"&gt;&lt;tr&gt;&lt;td&gt;
&lt;pre&gt;{
  FILE* f = (FILE *) 0;
  {
    f = fopen("c:/temp/foo.txt", "w");
    fprintf(f, "Hello, world");
  }
cleanup_8_:
  if (file) {
    fclose(file);
  }
}&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;Even if we add more complex code with multiple return paths, c-amplify
doesn&amp;#8217;t let us down:&lt;/p&gt;
&lt;table border="0" bgcolor="#e8e8e8" width="100%" cellpadding="10"&gt;&lt;tr&gt;&lt;td&gt;
&lt;pre&gt;(defun foo ((return int))
  (with-open-file (f "c:/temp/foo.txt" "w")
    (if (&amp;gt; (rand 10) 5)
       (return 20))
    (fprintf f "Hello, world")
    (return 10)))&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;This amplifies to the following C code. Note how the with-open-file
block locally redefines what it means to return a value. This C code
is a close representation of what a C++ compiler has to emit when RAII
is used but as before there are no residual types left.&lt;/p&gt;
&lt;table border="0" bgcolor="#e8e8e8" width="100%" cellpadding="10"&gt;&lt;tr&gt;&lt;td&gt;
&lt;pre&gt;int foo(void)
{
  FILE* f = (FILE *) 0;
  {
    int result_13_;
    {
      f = fopen("c:/temp/foo.txt", "w");
      if (rand(10) &amp;gt; 5) {
        result_13_ = 20;
        goto cleanup_12_;
      }
      fprintf(f, "Hello, world");
      {
        result_13_ = 10;
        goto cleanup_12_;
      }
    }
    cleanup_12_:
    if (f) {
      fclose(f);
    }
    return result_13_;
  }
}&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;One possible c-amplify implementation of the &lt;tt&gt;with-open-file&lt;/tt&gt; macro
looks like this (on a real game project it would of course not use
&lt;tt&gt;fopen&lt;/tt&gt;, but some custom file manager):&lt;/p&gt;
&lt;table border="0" bgcolor="#e8e8e8" width="100%" cellpadding="10"&gt;&lt;tr&gt;&lt;td&gt;
&lt;pre&gt;(def-c-macro with-open-file ((var file-name mode) &amp;amp;body body)
  `(progn
     (declare (,var = (cast (ptr #$FILE) 0)))
     (unwind-protect
          (progn
            (= ,var (#$fopen ,file-name ,mode))
            ,@body)
       (when ,var
         (#$fclose ,var)))))&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;The funny &lt;tt&gt;#$foo&lt;/tt&gt; syntax is just a reader macro to facilitate reading
case sensitive symbols in a special package which corresponds to the C
namespace. The implementation piggy-backs on &lt;tt&gt;unwind-protect&lt;/tt&gt;, which
makes sure that the body code always goes through the cleanup clauses:&lt;/p&gt;
&lt;table border="0" bgcolor="#e8e8e8" width="100%" cellpadding="10"&gt;&lt;tr&gt;&lt;td&gt;
&lt;pre&gt;(def-c-macro unwind-protect (form &amp;amp;body cleanup-forms)
  (with-c-gensyms (cleanup result)
    `(progn
       (ast-stmt-if (not (current-defun-void-p))
                    (declare (,result *current-return-type*)))
       (macrolet (return (&amp;amp;optional expr)
                         `(progn
                            (ast-stmt
                             (if (not (current-defun-void-p))
                                 `(= ,',',result ,,expr)
                                 `(cast void ,,expr)))
                            (goto ,',cleanup)))
         ,form)
       (label ,cleanup)
       ,@cleanup-forms
       (return ,result))))&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;If we decided to add exception handling (through e.g. &lt;tt&gt;setjmp&lt;/tt&gt; or SEH
exceptions), we only have to touch &lt;tt&gt;unwind-protect&lt;/tt&gt; to enable
exception cleanup in all our RAII-like resource macros. Layering pure
compile-time abstractions like this to create programs is incredibly
powerful.&lt;/p&gt;
&lt;h2&gt;&lt;a name="_exploiting_the_database"&gt;&lt;/a&gt;Exploiting the database&lt;/h2&gt;
&lt;p&gt;As I mentioned, there are many advantages to having all your code
parsed with type information sitting around in an in-memory
database. Let&amp;#8217;s highlight one such thing, automatic type inference
for local variables. Consider the following c-amplify input:&lt;/p&gt;
&lt;table border="0" bgcolor="#e8e8e8" width="100%" cellpadding="10"&gt;&lt;tr&gt;&lt;td&gt;
&lt;pre&gt;(defstruct bar
  (x (const restrict volatile ptr int)))

(defstruct foo
  (barp (ptr struct bar)))

(defun my-function ((foop (ptr struct foo)) (return int))
  (let ((xp (-&amp;gt; foop barp x)))
     (return (* xp))))&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;This amplifies to:&lt;/p&gt;
&lt;table border="0" bgcolor="#e8e8e8" width="100%" cellpadding="10"&gt;&lt;tr&gt;&lt;td&gt;
&lt;pre&gt;struct bar { int * const volatile restrict x; };

struct foo { struct bar * barp; };

int my_function(struct foo * foop) {
  int * const volatile restrict xp = foop-&amp;gt;barp-&amp;gt;x;
  return *xp;
}&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;p&gt;We can see that the lexical variable &lt;tt&gt;xp&lt;/tt&gt; has the expected type. The
c-amplify system knows how to compute the type of any C expression
(including arithmetic promotion) so the this feature can be used
extensively if desired.&lt;/p&gt;
&lt;h2&gt;&lt;a name="_including_what_8217_s_needed"&gt;&lt;/a&gt;Including what&amp;#8217;s needed&lt;/h2&gt;
&lt;p&gt;Another great feature of having a complete function/type database is
that generated C files do not need include statements. If a source
file needs a bunch of declarations the generator will just emit them
right there. There&amp;#8217;s no need to maintain header files. If code in a
generated file starts using a structure all of a sudden, a copy of its
declaration will automatically pop in to the generated file.&lt;/p&gt;
&lt;p&gt;For a full-out implementation of this idea to work, 3rd party
declarations from the OS and C libraries must be imported into the
amplification database. A separate tool must be devised for this but
it would certainly be possible.&lt;/p&gt;
&lt;p&gt;Compiling files generated like this would mean the the preprocessor
wouldn&amp;#8217;t touch disk except to read the input c file. Makefiles for
generated files such as these will also be trivial to write as there
are no implicit dependencies.&lt;/p&gt;
&lt;h2&gt;&lt;a name="_further_ideas"&gt;&lt;/a&gt;Further ideas&lt;/h2&gt;
&lt;p&gt;Here are additional ideas that could be explored within the c-amplify
system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;
Improved compile-time checking for traditionally dangerous functions
  (&lt;tt&gt;scanf&lt;/tt&gt;, &lt;tt&gt;printf&lt;/tt&gt;) (make macros that evaluate the format strings
  and types of arguments)
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Add exception handling to C on top of &lt;tt&gt;setjmp&lt;/tt&gt;, SEH or some other
  basic mechanism
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Annotate structures for real-time tweaking.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Generate script language bindings at compile time via macros and
  hooks.
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Inlining/code simplification at amplification time (trig function
  simplification, maths)
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
Add a proper sublanguage for vector math. Finally you can write that
  vector math library that combines plus and multiply to &lt;tt&gt;madd&lt;/tt&gt; on
  altivec by analyzing the code at compile time, and you don&amp;#8217;t need
  3000 lines of C++ "expression templates" to do it
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
If you absolutely must have C++-like classes and templates, you
  could implement those too. Classes with single dispatch would be
  pretty easy (generate a couple of structs per class), and templates
  could be "done right" in the sense that you&amp;#8217;d only generate a single
  expansion for each instantiated type and dump them all to a single
  source file, rather than compiling thousands of instantiations of
  &lt;tt&gt;std::vector&lt;/tt&gt; and letting the linker sort through the carnage.
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a name="_conclusion"&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;If there is a way (no matter how much work it would be) to express the
semantics of an abstraction in C, chances are you can implement it as
a set of macros and hooks in c-amplify.&lt;/p&gt;
&lt;p&gt;However, c-amplify is still a prototype and a lot of work remains
before it might be suitable for production use. I hope this rant has
given you some new ideas on how we design programs. Send your feedback
and flames my way.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-1030759976264022429?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/1030759976264022429/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=1030759976264022429' title='36 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/1030759976264022429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/1030759976264022429'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2010/01/amplifying-c.html' title='Amplifying C'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>36</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-7726161733747231096</id><published>2009-04-19T13:29:00.006+02:00</published><updated>2010-01-31T14:29:42.626+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='amiga'/><title type='text'>Amiga remote launching</title><content type='html'>I've been working with TBL on an Amiga production recently. Hardly anyone develops on the real Amiga hardware anymore. A modern PC is nice to develop on, but it's a pain to copy over the program and related test files for every test run.&lt;br /&gt;
&lt;br /&gt;
Well, no more copying! Taking from console development tools from I've crafted a remote command launcher for the Amiga that can run arbitrary programs over a TCP/IP link and channel back file I/O too. You even get the standard output back locally, it's cross-development bliss :)&lt;br /&gt;
&lt;br /&gt;
More details in the &lt;a href="http://aminet.net/package/dev/cross/rlaunch"&gt;Aminet release&lt;/a&gt; where you can download the programs for Win32 and Amiga.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-7726161733747231096?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/7726161733747231096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=7726161733747231096' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/7726161733747231096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/7726161733747231096'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2009/04/amiga-remote-launching.html' title='Amiga remote launching'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-2569601867400162098</id><published>2009-01-22T01:01:00.005+01:00</published><updated>2009-01-22T01:08:57.534+01:00</updated><title type='text'>ReadyNAS NV+ UPS monitoring</title><content type='html'>I just got one of these and a APC Smart-UPS 750 to back it up along with my little version control server at home.

The ReadyNAS uses &lt;a href="http://www.networkupstools.org"&gt;nut &lt;/a&gt;so it was pretty easy to make it slave to the Linux server which is polling the UPS status. Unfortunately the ReadyNAS only allows you to specify a master IP, but it works fine if you hardcode the user name, password and UPS name it expects:

&lt;span style="font-style: italic;"&gt;/etc/nut/upsd.users&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;[monuser]&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        password pass&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        allowfrom = local remote&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        upsmon master&lt;/span&gt;

&lt;span style="font-style: italic;"&gt;/etc/nut/ups.conf&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;[UPS]&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        driver = apcsmart&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        port = /dev/ttyS0&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        desc = "APC Smart-UPS 750"&lt;/span&gt;

(Remote above should be configured as an ACL for your LAN.)

With these setting it's just a matter of entering your UPS monitoring master's IP in the ReadyNAS configuration frontend and it will connect. A quick battery test shows that the events cascade from the master to the ReadyNAS:

&lt;table id="lul" width="95%" align="center" border="0" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr class="gray"&gt;&lt;td style="font-style: italic;" rowspan="1" colspan="1" char="." valign="top" align="left" nowrap="nowrap"&gt;&lt;span id="time_1" class="field-lite-small"&gt;Thu Jan 22 00:57:00 CET 2009&lt;/span&gt;&lt;/td&gt;&lt;td style="font-style: italic;" rowspan="1" colspan="1" char="." valign="top" align="left"&gt;&lt;span id="description_1" class="field-small"&gt;UPS is on line power.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-style: italic;" rowspan="1" colspan="1" char="." valign="top" align="left" nowrap="nowrap"&gt;&lt;span id="time_2" class="field-lite-small"&gt;Thu Jan 22 00:56:51 CET 2009&lt;/span&gt;&lt;/td&gt;&lt;td style="font-style: italic;" rowspan="1" colspan="1" char="." valign="top" align="left"&gt;&lt;span id="description_2" class="field-small"&gt;UPS is on battery power.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
You even get popups in the frontend!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-2569601867400162098?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/2569601867400162098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=2569601867400162098' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/2569601867400162098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/2569601867400162098'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2009/01/readynas-nv-ups-monitoring.html' title='ReadyNAS NV+ UPS monitoring'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-1009556992341379206</id><published>2008-12-04T17:31:00.007+01:00</published><updated>2008-12-04T19:32:55.298+01:00</updated><title type='text'>Fix for the ClearType pixel junk in GVIM</title><content type='html'>&lt;p&gt;
&lt;img src="http://2.bp.blogspot.com/_2P1ZGKDPDM0/STgGi94QzoI/AAAAAAAAABA/xeVTPULL9uw/s320/bug.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5275974161260400258" /&gt;
&lt;/p&gt; &lt;p&gt;
&lt;i&gt;Update: This doesn't work for fonts that use the right-most column. In fact the issue seems to be cleartype writing outside the leftmost pixel in the bounding box. :-(
&lt;/i&gt;
&lt;/p&gt; &lt;p&gt;
&lt;br /&gt;
Here's a fix for this super-annoying bug (Lucida Console 11, insert spaces before the C to leave a trail of cleartype pixels). &lt;pre&gt;
===================================================================
--- gui_w32.c   (revision 1289)
+++ gui_w32.c   (working copy)
@@ -2234,6 +2234,8 @@
         * Note: FillRect() excludes right and bottom of rectangle.
         */
        rc.left = FILL_X(col);
+       if (rc.left &gt; 0)
+           --rc.left;
        rc.top = FILL_Y(row);
 #ifdef FEAT_MBYTE
        if (has_mbyte)
&lt;/pre&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-1009556992341379206?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/1009556992341379206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=1009556992341379206' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/1009556992341379206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/1009556992341379206'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2008/12/fix-for-cleartype-pixel-junk-in-gvim.html' title='Fix for the ClearType pixel junk in GVIM'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_2P1ZGKDPDM0/STgGi94QzoI/AAAAAAAAABA/xeVTPULL9uw/s72-c/bug.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-6054290835194649872</id><published>2008-09-01T23:03:00.003+02:00</published><updated>2008-09-01T23:06:22.910+02:00</updated><title type='text'>Querying Wow64 registry keys from a 64-bit Python</title><content type='html'>KEY_WOW64_32KEY gets the job done
&lt;pre&gt;
import _winreg

key = None
KEY_WOW64_32KEY = 0x0200

try:
  key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, \
    r"SOFTWARE\Microsoft\VisualStudio\9.0", 0, \
    _winreg.KEY_READ | KEY_WOW64_32KEY)
  val, type = _winreg.QueryValueEx(key, "InstallDir")
  print val
except EnvironmentError, ex:
  print ex
finally:
  if key:
    _winreg.CloseKey(key)
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-6054290835194649872?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/6054290835194649872/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=6054290835194649872' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/6054290835194649872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/6054290835194649872'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2008/09/querying-wow64-registry-keys-from-64.html' title='Querying Wow64 registry keys from a 64-bit Python'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-37209196705460784</id><published>2008-02-16T21:40:00.004+01:00</published><updated>2008-04-25T09:43:39.158+02:00</updated><title type='text'>Hardware Inventory</title><content type='html'>Turning the basement upside down yielded
&lt;ul&gt;&lt;li&gt;2 Commodore 64s (old style breadbox, one white and one brown)&lt;/li&gt;&lt;li&gt;2 1541 old-school drives (brown enclosure)
&lt;/li&gt;&lt;li&gt;A Commodore 128&lt;/li&gt;&lt;li&gt;A 1541-II drive&lt;/li&gt;&lt;li&gt;An Amiga 500 w/ old-school slow 512 kb expansion memory&lt;/li&gt;&lt;li&gt;TrumpCard SCSI sidecar enclosure for A500&lt;/li&gt;&lt;li&gt;External memory expansion (2 MB) for A500&lt;/li&gt;&lt;li&gt;Power adapters for most of above&lt;/li&gt;&lt;li&gt;Extra floppy drives for Amigas
&lt;/li&gt;&lt;li&gt;An Amiga 1200 vanilla&lt;/li&gt;&lt;li&gt;A HP-UX workstation box of unknown origin&lt;/li&gt;&lt;li&gt;A 680x0-based SUN box
&lt;/li&gt;&lt;li&gt;Two SGI Octanes&lt;/li&gt;&lt;li&gt;External CD-ROM SCSI enclosures for the SGIs&lt;/li&gt;&lt;li&gt;And a shitload of cables and PSUs&lt;/li&gt;&lt;/ul&gt;Continuing upstairs:
&lt;ul&gt;&lt;li&gt;One dual Opteron server (disconnected)&lt;/li&gt;&lt;li&gt;One Athlon-based generic Linux box (serving)&lt;/li&gt;&lt;li&gt;One desktop box&lt;/li&gt;&lt;li&gt;Another desktop box from el cheapo gear (dell)&lt;/li&gt;&lt;li&gt;A laptop&lt;/li&gt;&lt;li&gt;A fanless mini-server&lt;/li&gt;&lt;/ul&gt;Update:
New addition: Amiga 1200 w/ 060 and an 14" CRT.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-37209196705460784?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/37209196705460784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=37209196705460784' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/37209196705460784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/37209196705460784'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2008/02/hardware-inventory.html' title='Hardware Inventory'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-5178570439190419030</id><published>2007-09-09T00:47:00.001+02:00</published><updated>2007-09-09T00:55:28.769+02:00</updated><title type='text'>hash_map band aid</title><content type='html'>Until TR1 is widely available, I'm using this wrapper to construct hash maps using the hash_maps distributed with Visual C++ and GCC. I thought it might be useful for someone else, so here goes.
&lt;pre&gt;
#if defined(_MSC_VER)
#include &amp;lt;hash_map&amp;gt;
#elif defined(__GNUC__)
#include &amp;lt;ext/hash_map&amp;gt;
#endif

template &amp;lt;typename K&amp;gt; struct default_hash {};

template &amp;lt;&amp;gt; struct default_hash&amp;lt;int&amp;gt; {
 size_t operator()(int v) const
    { return size_t(v); }
};

template &amp;lt;&gt; struct default_hash&amp;lt;unsigned int&amp;gt; {
 size_t operator()(unsigned int v) const
    { return size_t(v); }
};

#if defined(_MSC_VER)

template &amp;lt;
 typename KeyType,
 typename ValueType,
 class HashFun = default_hash&amp;lt;KeyType&amp;gt;
 &amp;gt;
struct HashMapOf
{
 struct Traits
 {
  static const size_t bucket_size = 4;
  static const size_t min_buckets = 8;

  HashFun hasher;

  inline size_t operator()
    (const KeyType&amp; key) const
  {
   return hasher(key);
  }

  inline bool operator()
     (const KeyType&amp; lhs,
      const KeyType&amp; rhs) const
  {
   return lhs &amp;lt; rhs;
  }
 };


 typedef stdext::hash_map&amp;lt;
    KeyType,
    ValueType,
    Traits&amp;gt; Type;
};

#elif defined(__GNUC__)

template &amp;lt;
 typename KeyType,
 typename ValueType,
 class HashFun = default_hash&amp;lt;KeyType&amp;gt;
 &amp;gt;
struct HashMapOf
{
 typedef __gnu_cxx::hash_map&amp;lt;
    KeyType,
    ValueType,
    HashFun&amp;gt; Type;
};

#else
# error Unsupported toolchain.
#endif

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-5178570439190419030?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/5178570439190419030/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=5178570439190419030' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/5178570439190419030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/5178570439190419030'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2007/09/hashmap-band-aid.html' title='hash_map band aid'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-4044922888288450347</id><published>2007-02-18T17:32:00.000+01:00</published><updated>2007-02-18T18:06:35.249+01:00</updated><title type='text'>Vista and Visual Studio, Oil and Water</title><content type='html'>So I've installed Vista (Ultimate, in fact), but Visual Studio 2005 seems like a terrible Vista citizen. In order to run it you need to apply the service pack, but also a beta version of a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;hotfix&lt;/span&gt; package. Even then, Microsoft recommends you run Visual Studio as Administrator.

Now, I ask myself: Does compiling source code demand complete access to the entire box? On Vista, that's apparently the case. It seemed to work fine on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;XP&lt;/span&gt;.

Now to the most juicy bug of the day. Once you've started a debugging session from within Visual Studio, the target &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;EXE&lt;/span&gt; file becomes locked. Closing Visual Studio removes the lock, but the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;devenv&lt;/span&gt; process doesn't hold any handles to the file. What gives? I'm starting to suspect that the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;SUA&lt;/span&gt; services might have something to do with this, so they're &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;uninstalling&lt;/span&gt; right now.

It's pretty annoying to restart the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;IDE&lt;/span&gt; after each debugging session to be able to recompile.

&lt;strong&gt;Update&lt;/strong&gt;

I've identified SUA to be the problem. After uninstalling the SDK and removing the windows services it installs, I can recompile and debug again.. For now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-4044922888288450347?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/4044922888288450347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=4044922888288450347' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/4044922888288450347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/4044922888288450347'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2007/02/vista-and-visual-studio-oil-and-water.html' title='Vista and Visual Studio, Oil and Water'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-2841732059438186551</id><published>2007-02-14T20:10:00.000+01:00</published><updated>2007-02-14T20:35:25.482+01:00</updated><title type='text'>The pleasures of a stable ABI</title><content type='html'>As broken as the Win32 API might appear, the thing I really like about it is its stable ABI. That, and the fact that Microsoft spend thousands of hours making sure that old programs work when they release a new version of Windows is worth a lot to me. Solaris has a decent ABI, and I assume most other unices have too. What would it take for Linux to achieve the same level of stability?

The Linux kernel does have a fairly stable ABI as long as you say away from the &lt;span style="font-family:courier new;"&gt;proc&lt;/span&gt; file system and device nodes (devfs and whatnot come and go). The C library is also well designed. Most issues with Linux binary (in)compatibility have been in the C++ libraries. The C++ libraries have changed ABIs with each and every version of the compiler, sometimes even breaking with point releases.

Breaking the C++ ABI isn't a problem in itself, it happens with the Visual Studio compilers all the time. The real problem is that when deployed, Linux binaries depend on the distribution to include a suitable C++ runtime library to which they can dynamically link, whereas on Windows, programs either carry their C++ runtime with them (pre-VC8) or rely on a separate distributable that can be installed side-by-side in the DLL cache so that a compatible version is always available.

For the Battlefield Linux server builds I had this exact problem. I had to use at least GCC 3.x as GCC 2.x was (and still is) a severely outdated compiler without proper namespace support. However, using GCC 3.x meant that people with rented servers that ran older versions of Red Hat were left out in the cold, unless they could find a standard C++ library that would somehow let them run the binary! This was seen as a Bad Thing.

The only solution I could think of at the time was to provide a statically linked executable in addition to the regular executable, so that older systems had a hope in hell to run it. That required me to tweak and override certain symbols of the standard library to avoid them from referencing versioned symbols from glibc that weren't present on the target systems, and the whole things was just a terrible mess that took too much time.

In the end, linking statically turned out to be somewhat illegal (as we couldn't satisfy the LGPL on that binary) so that option had to be removed. I considered it fair use because there was indeed a dynamically linked executable available as well that did satisfy the LGPL, but it was thought safer to drop it.

It would have been so much nicer to ship a C++ library redistributable for x86 and amd64 and let users install it if needed..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-2841732059438186551?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/2841732059438186551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=2841732059438186551' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/2841732059438186551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/2841732059438186551'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2007/02/pleasures-of-stable-abi.html' title='The pleasures of a stable ABI'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-116462302565307279</id><published>2006-11-27T10:56:00.000+01:00</published><updated>2006-11-27T11:27:31.840+01:00</updated><title type='text'>ODE, .NET, handles and references from hell</title><content type='html'>I've recently toyed around with .NET in C# and I was excited to see that there are .NET bindings for a lot of free game development libraries in the Tao framework.

I was especially interested in playing with the ODE bindings. ODE is a free physics and collision library that is starting to become usable for a lot of things. As with many .NET wrappers, the ODE wrapper is just a set of static functions that take System.IntPtr objects. You are supposed to juggle these handles carefully, because they correspond to some real unmanaged object.

This is all good, but these APIs break down when the unmanaged objects form graphs on their own, which is the case with the ODE API. Assume we have a wrapper for the following API:

&lt;span style="font-family:courier new;"&gt;public sealed class SomeApi {
&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&amp;nbsp;static IntPtr MakeContainer();
&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&amp;nbsp;static void DestroyContainer(IntPtr i);

&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&amp;nbsp;static IntPtr MakeItem();
&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&amp;nbsp;static void DestroyItem(IntPtr i);&lt;/span&gt;

&lt;span style="font-family:courier new;"&gt;&amp;nbsp;static void AddItem(IntPtr container, IntPtr item);
&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;  // Many other functions.
&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;

Further, assume that the semantics of a "Container" in the API is that it destroys its contents when it is destroyed. Also assume that we've written our wrapper classes for Container and Item so that they correctly call the corresponding cleanup function in the API when objects are Disposed and finalized.

With the prerequisites out of the way, consider this code fragment:

&lt;span style="font-family:courier new;"&gt;Item i = new Item();&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;Container c = new Container();&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;c.AddItem(i);&lt;/span&gt;

What is happening here is that the unmanaged code is forming a reference graph behind the covers, but the available tools for dealing with unmanaged resources can't see such graphs. The .NET process will crash because regardless of whether the item or the container is destroyed/finalized first, the other one still refers to a (now deleted) unmanaged object. 

Tao's ODE wrapper exhibits these exact problems, making it very hard to reason about code correctness. Essentially I'm finding it much harder to use in C# than in C because not only do I have to deal with my own code, I also have to consider how ODE maintains memory internally at every API invocation and what that does to the validness of my wrapper objects.

The only solution I can see is to build wrapper APIs that explicitly maintain the life-time of handles as well. In the above example, such a wrapper would detect that the "AddItem" operation changes the cleanup origin of the item and that it shouldn't be destroyed when the Item wrapper is destroyed, because the container is now doing that.

Sigh.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-116462302565307279?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/116462302565307279/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=116462302565307279' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/116462302565307279'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/116462302565307279'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2006/11/ode-net-handles-and-references-from.html' title='ODE, .NET, handles and references from hell'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-114968800697185616</id><published>2006-06-07T15:46:00.000+02:00</published><updated>2006-06-07T15:46:47.006+02:00</updated><title type='text'>Non-ignorable return codes</title><content type='html'>I'd like to have a nonignorable-type that could be used to wrap return values that must be handled, but using an exception would be to heavy-weight.

Consider:

&lt;span style="font-family:courier new;"&gt;bool IntersectLineAndPlane(...);&lt;/span&gt;

I'd like to say

&lt;span style="font-family:courier new;"&gt;nonignorable&amp;lt;bool&amp;gt; IntersectLineAndPlane(...);&lt;/span&gt;

And then have code that doesn't handle the return value give a compile-time error (or warning) so that mistakes don't slip through into production code.

You would think that perhaps something like this would work:
&lt;pre style="font-family: courier new;"&gt;
template &amp;lt;typename T&amp;gt;
class nonignorable {
  public:
      nonignorable(const T&amp; v) : value_(v) {}

      // check() does the destruction and extracts the value
      friend T check(const nonignorable&amp;lt;T&amp;gt;&amp;amp;);

 private:
     ~nonignorable();
};
&lt;/pre&gt;

This could be used as:
&lt;pre style="font-family: courier new;"&gt;
nonignorable&amp;lt;bool&amp;gt; Function() {
 return nonignorable&lt;bool&gt;(false);
}&lt;/bool&gt;&lt;/pre&gt;

And in client code:

&lt;span style="font-family:courier new;"&gt;if (!check(Function)) { /* take action */ }&lt;/span&gt;

Alas, this will not work, because there are more destructions going on when the nonignorable instance is returned on the stack. I think the only way to solve this is to rely on the new C++0x proposition to add move semantics into the language so that there is only one destruction (in the check() template function).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-114968800697185616?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/114968800697185616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=114968800697185616' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/114968800697185616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/114968800697185616'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2006/06/non-ignorable-return-codes.html' title='Non-ignorable return codes'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-114262908783135113</id><published>2006-03-17T21:48:00.000+01:00</published><updated>2006-03-17T22:03:47.303+01:00</updated><title type='text'>Mixing Scheme and C</title><content type='html'>In my quest to find the perfect Scheme/C mix I've found that Bigloo Scheme really goes a long way to overcome the language barriers. The cool part is that Bigloo compiles to efficient C code, and you can influence the generated code in a number of ways. For example, it's possible to include headers and declare functions with type annotations straight in the Scheme source code.

Since the Scheme files are translated to C when compiled, there's no marshalling to consider. I'm assuming that annotated procedures yield a very low overhead compared to Python which requires a object allocations for everything (even integers).

Using Bigloo with DLLs symbols on windows has one quirk though, the symbols must be imported as macros, and the header file with &lt;span style="font-family:courier new;"&gt;_declspec()&lt;/span&gt; crud must be included explicitly.

This does the trick:
&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;(module my-module&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;        (extern&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;          (include "include/mydll.h")&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;          (macro simple::int (::int) "simple")))&lt;/span&gt;&lt;/pre&gt;
Given these declarations, you can call the function &lt;span style="font-family: courier new;"&gt;simple&lt;/span&gt; as if it were a Scheme procedure, which is awesome. When compiled, the resulting executable links properly to the DLL. I haven't found a tool that can produce these annotations automatically, but writing one should be trivial.

I'm slightly confused about how to make a stringent build system for a combined Scheme/C project, but I'm sure it's possible. Armed with such a build tool it might actually become fun to program again..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-114262908783135113?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/114262908783135113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=114262908783135113' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/114262908783135113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/114262908783135113'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2006/03/mixing-scheme-and-c.html' title='Mixing Scheme and C'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22374588.post-113994750684188778</id><published>2006-02-14T21:01:00.000+01:00</published><updated>2006-02-14T21:52:17.596+01:00</updated><title type='text'>Reducing boilerplate by embedding XSLT</title><content type='html'>I've recently been working on an custom IDL compiler that can target Python and C++. Think COM, only portable between platforms and targeted towards a select few languages. A lot of patterns immediately appear in both the frontend and backends of the compiler that's just boilerplate work. Consider the classic implementation of an IDL parser (or any programming language parser, for that matter):
&lt;ol&gt;&lt;li&gt;Parse the input, building an abstract syntax tree of the declarations.&lt;/li&gt;&lt;li&gt;Build a type graph and interconnect the type nodes so that types can be resolved.&lt;/li&gt;&lt;li&gt;Resolve all type references (using fixups or in a separate pass if forward references allowed.)&lt;/li&gt;&lt;li&gt;Invoke one or more backends if the resulting tree is valid.
&lt;/li&gt;&lt;/ol&gt; The backends in turn will walk the tree (via some variation of the Visitor pattern) and produce output. This quickly becomes repetitive and mundane work. Visitor is well known for it's strong impact on code coupling and strong binding between entities.

In another sandbox project of mine I tried out a completely different approach. Instead of writing yet another AST hierarchy to interface the frontend I experimented with XML as an intermediate format in the compiler itself. Given an input file, my LALR parser will essentially emit a well-formed XML document using the DOM APIs. This in itself doesn't buy much, but it provides tremendous flexibility down the road. Think of it as capturing the entire AST in a portable format. Indeed, the GCC project has recently added a AST-to-XML converter as part of their (excellent) compiler frontend so more people are thinking along these lines.

With the AST swimming around in an XML DOM tree, it becomes possible to rewrite repetitive and boring tasks in XML query tools that are designed for those jobs rather than a general-purpose programming language such as C++. Whipping up flexible type resolvers, type and syntax checkers using a decent XSLT processor is a lot of fun, and it can be done with a surprisingly small amount of XSLT code. XQuery processors can easily build statistics and metrics with a minimal amount of code.

Another interesting thing about keeping the AST in XML is that it becomes trivial to add whatever meta-data you like in a matter of seconds. That data can travel through the filters (for example in an XML namespace of its own) all the way to the backend, where it can be used to tweak the output. Also, changing the XML AST doesn't require recompiling hundreds of AST classes!

The key concept to making this work is pipelining, which is a common design pattern anyway in compilers. Connecting the output of one XSLT processing filter to the input of the next nicely captures the pipelining pattern while at the same time enforcing the idea that one piece of code should have a single, well-defined purpose. XSLT also works wonders for code generation backends, because it designed for transforming data, something C++, Java and Python simply aren't.

So what are the drawbacks? Simply put: speed and memory consumption. Clearly, a hand-written implementation of say a type resolver will have a lower memory consumption and better processing speed than a XSLT-based implementation. Also, while XSLT is a very useful language (especially with version 2) it's not very strong with error reporting or string handling, to name a few areas. If you're willing to strike a deal with the portability devil and settle on a single XSLT library it's possible to work around most of these problems.

Given the prototyping advantages I still think this is a viable implementation strategy for compiler projects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22374588-113994750684188778?l=voodoo-slide.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://voodoo-slide.blogspot.com/feeds/113994750684188778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22374588&amp;postID=113994750684188778' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/113994750684188778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22374588/posts/default/113994750684188778'/><link rel='alternate' type='text/html' href='http://voodoo-slide.blogspot.com/2006/02/reducing-boilerplate-by-embedding-xslt.html' title='Reducing boilerplate by embedding XSLT'/><author><name>dep</name><uri>http://www.blogger.com/profile/16229508667482062327</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='25' src='http://1.bp.blogspot.com/_2P1ZGKDPDM0/TH-bhLwfvlI/AAAAAAAABAE/3X2QogezSUM/S220/profile-blur.jpg'/></author><thr:total>0</thr:total></entry></feed>
