<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sufficiently Small &#187; .NET</title>
	<atom:link href="http://www.smallshire.org.uk/sufficientlysmall/category/computing/software/net/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.smallshire.org.uk/sufficientlysmall</link>
	<description>sin(x) = x</description>
	<lastBuildDate>Sun, 01 Jan 2012 23:29:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>A Hindley-Milner type inference implementation in Python</title>
		<link>http://www.smallshire.org.uk/sufficientlysmall/2010/04/11/a-hindley-milner-type-inference-implementation-in-python/</link>
		<comments>http://www.smallshire.org.uk/sufficientlysmall/2010/04/11/a-hindley-milner-type-inference-implementation-in-python/#comments</comments>
		<pubDate>Sun, 11 Apr 2010 19:36:07 +0000</pubDate>
		<dc:creator>Robert Smallshire</dc:creator>
				<category><![CDATA[computing]]></category>
		<category><![CDATA[Functional programming]]></category>
		<category><![CDATA[OWL BASIC]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.smallshire.org.uk/sufficientlysmall/?p=474</guid>
		<description><![CDATA[A Python implementation of a Hindley-Milner type inferencing algorithm for a small functional language.]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2010%2F04%2F11%2Fa-hindley-milner-type-inference-implementation-in-python%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2010%2F04%2F11%2Fa-hindley-milner-type-inference-implementation-in-python%2F&amp;source=robsmallshire&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><strong>Before you get too excited this is an implementation of a type inference algorithm that happens to be written in Python; it has nothing to do with the Python language itself!</strong></p>
<p>I&#8217;ve been working on <a href="http://www.smallshire.org.uk/sufficientlysmall/category/computing/software/net/owl-basic/">OWL BASIC</a>, a compiler for <a href="http://en.wikipedia.org/wiki/BBC_BASIC">BBC BASIC</a> for the .NET CLR. The compiler itself is written in IronPython.  One of the challenges of compiling BBC BASIC is to infer the types of functions from the type of their return types. The return value of a BBC BASIC function can be an arbitrary expression, including calls to other functions or recursive calls to itself.  I&#8217;ve implemented a simple type inference scheme which works well in the common cases, but for a fully capable solution my type checker and type inferencer need to be beefed up somewhat.  To that end, I&#8217;ve been investigating standard type systems such as Hindley-Milner and inferencing algorithms such as Damas-Milner, sometimes known as Algorithm W.  These algorithms or derivatives thereof are using in the ML family of languages (Standard ML, Ocaml, F#) and Haskell.</p>
<p>I managed to locate a <a href="http://lucacardelli.name/Papers/BasicTypechecking.pdf#page=19">Modula-2 implementation</a>, a <a href="http://web.archive.org/web/20050911123640/http://www.cs.berkeley.edu/~nikitab/courses/cs263/hm.html">Perl implementation</a> and a <a href="http://dysphoria.net/2009/06/28/hindley-milner-type-inference-in-scala/">Scala implementation</a> of the algorithm, each descended from the previous.  With a view to improving my understanding of the algorithm I set about reimplementing in Python, largely guided by the Scala implementation, making mine the fourth in this sequence.  I also located a <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.65.7733&#038;rep=rep1&#038;type=pdf">Haskell implementation</a> which seems to have independent ancestry.  I&#8217;ve gone back to the companion paper (<a href="http://lucacardelli.name/Papers/BasicTypechecking.pdf">Cardelli 1987</a>) to the original Modula-2 implementation and carried forward some of the code comments which had been omitted from its descendants to assist others who wish to understand the algorithm.</p>
<p>The program implements abstract syntax tree nodes for a small functional language, the type inferencing algorithm and finally exercises the algorithm by inferring the types of some canned expressions in the context of some predefined types. When executed it produces the following output:</p>
<pre class="brush: plain; title: ; notranslate">
&gt; python hindley_milner.py
(letrec factorial = (fn n =&gt; (((cond (zero n)) 1) ((times n) (factorial (pred n))))) in (factorial 5)) :  int
(fn x =&gt; ((pair (x 3)) (x true))) :  Type mismatch: bool != int
((pair (f 4)) (f true)) :  Undefined symbol f
(let f = (fn x =&gt; x) in ((pair (f 4)) (f true))) :  (int * bool)
(fn f =&gt; (f f)) :  recursive unification
(let g = (fn f =&gt; 5) in (g g)) :  int
(fn g =&gt; (let f = (fn x =&gt; g) in ((pair (f 3)) (f true)))) :  (a -&gt; (a * a))
(fn f =&gt; (fn g =&gt; (fn arg =&gt; (g (f arg))))) :  ((b -&gt; c) -&gt; ((c -&gt; d) -&gt; (b -&gt; d)))
</pre>
<p>The Python code is shown below in its entirety or it can be downloaded as <a href="http://www.smallshire.org.uk/downloads/hindley_milner.py">hindley_milner.py</a>. It will run without modification on Python 2.6 or Python 3. </p>
<pre class="brush: python; title: ; notranslate">
#!/usr/bin/env python
'''
.. module:: hindley_milner
   :synopsis: An implementation of the Hindley Milner type checking algorithm
              based on the Scala code by Andrew Forrest, the Perl code by
              Nikita Borisov and the paper &quot;Basic Polymorphic Typechecking&quot;
              by Cardelli.
.. moduleauthor:: Robert Smallshire
'''

from __future__ import print_function

#=======================================================#
# Class definitions for the abstract syntax tree nodes
# which comprise the little language for which types
# will be inferred

class Lambda(object):
    &quot;&quot;&quot;Lambda abstraction&quot;&quot;&quot;

    def __init__(self, v, body):
        self.v = v
        self.body = body

    def __str__(self):
        return &quot;(fn {v} =&gt; {body})&quot;.format(v=self.v, body=self.body)

class Ident(object):
    &quot;&quot;&quot;Identfier&quot;&quot;&quot;

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

class Apply(object):
    &quot;&quot;&quot;Function application&quot;&quot;&quot;

    def __init__(self, fn, arg):
        self.fn = fn
        self.arg = arg

    def __str__(self):
        return &quot;({fn} {arg})&quot;.format(fn=self.fn, arg=self.arg)

class Let(object):
    &quot;&quot;&quot;Let binding&quot;&quot;&quot;

    def __init__(self, v, defn, body):
        self.v = v
        self.defn = defn
        self.body = body

    def __str__(self):
        return &quot;(let {v} = {defn} in {body})&quot;.format(v=self.v, defn=self.defn, body=self.body)

class Letrec(object):
    &quot;&quot;&quot;Letrec binding&quot;&quot;&quot;

    def __init__(self, v, defn, body):
        self.v = v
        self.defn = defn
        self.body = body

    def __str__(self):
        return &quot;(letrec {v} = {defn} in {body})&quot;.format(v=self.v, defn=self.defn, body=self.body)

#=======================================================#
# Exception types

class TypeError(Exception):
    &quot;&quot;&quot;Raised if the type inference algorithm cannot infer types successfully&quot;&quot;&quot;

    def __init__(self, message):
        self.__message = message

    message = property(lambda self: self.__message)

    def __str__(self):
        return str(self.message)

class ParseError(Exception):
    &quot;&quot;&quot;Raised if the type environment supplied for is incomplete&quot;&quot;&quot;
    def __init__(self, message):
        self.__message = message

    message = property(lambda self: self.__message)

    def __str__(self):
        return str(self.message)

#=======================================================#
# Types and type constructors

class TypeVariable(object):
    &quot;&quot;&quot;A type variable standing for an arbitrary type.

    All type variables have a unique id, but names are only assigned lazily,
    when required.
    &quot;&quot;&quot;

    next_variable_id = 0

    def __init__(self):
        self.id = TypeVariable.next_variable_id
        TypeVariable.next_variable_id += 1
        self.instance = None
        self.__name = None

    next_variable_name = 'a'

    def _getName(self):
        &quot;&quot;&quot;Names are allocated to TypeVariables lazily, so that only TypeVariables
        present
        &quot;&quot;&quot;
        if self.__name is None:
            self.__name = TypeVariable.next_variable_name
            TypeVariable.next_variable_name = chr(ord(TypeVariable.next_variable_name) + 1)
        return self.__name

    name = property(_getName)

    def __str__(self):
        if self.instance is not None:
            return str(self.instance)
        else:
            return self.name

    def __repr__(self):
        return &quot;TypeVariable(id = {0})&quot;.format(self.id)

class TypeOperator(object):
    &quot;&quot;&quot;An n-ary type constructor which builds a new type from old&quot;&quot;&quot;

    def __init__(self, name, types):
        self.name = name
        self.types = types

    def __str__(self):
        num_types = len(self.types)
        if num_types == 0:
            return self.name
        elif num_types == 2:
            return &quot;({0} {1} {2})&quot;.format(str(self.types[0]), self.name, str(self.types[1]))
        else:
            return &quot;{0} {1}&quot; % (self.name, ' '.join(self.types))

class Function(TypeOperator):
    &quot;&quot;&quot;A binary type constructor which builds function types&quot;&quot;&quot;

    def __init__(self, from_type, to_type):
        super(Function, self).__init__(&quot;-&gt;&quot;, [from_type, to_type])

# Basic types are constructed with a nullary type constructor
Integer = TypeOperator(&quot;int&quot;, [])  # Basic integer
Bool    = TypeOperator(&quot;bool&quot;, []) # Basic bool

#=======================================================#
# Type inference machinery

def analyse(node, env, non_generic=None):
    &quot;&quot;&quot;Computes the type of the expression given by node.

    The type of the node is computed in the context of the context of the
    supplied type environment env. Data types can be introduced into the
    language simply by having a predefined set of identifiers in the initial
    environment. environment; this way there is no need to change the syntax or, more
    importantly, the type-checking program when extending the language.

    Args:
        node: The root of the abstract syntax tree.
        env: The type environment is a mapping of expression identifier names
            to type assignments.
            to type assignments.
        non_generic: A set of non-generic variables, or None

    Returns:
        The computed type of the expression.

    Raises:
        TypeError: The type of the expression could not be inferred, for example
            if it is not possible to unify two types such as Integer and Bool
        ParseError: The abstract syntax tree rooted at node could not be parsed
    &quot;&quot;&quot;

    if non_generic is None:
        non_generic = set()

    if isinstance(node, Ident):
        return getType(node.name, env, non_generic)
    elif isinstance(node, Apply):
        fun_type = analyse(node.fn, env, non_generic)
        arg_type = analyse(node.arg, env, non_generic)
        result_type = TypeVariable()
        unify(Function(arg_type, result_type), fun_type)
        return result_type
    elif isinstance(node, Lambda):
        arg_type = TypeVariable()
        new_env = env.copy()
        new_env[node.v] = arg_type
        new_non_generic = non_generic.copy()
        new_non_generic.add(arg_type)
        result_type = analyse(node.body, new_env, new_non_generic)
        return Function(arg_type, result_type)
    elif isinstance(node, Let):
        defn_type = analyse(node.defn, env, non_generic)
        new_env = env.copy()
        new_env[node.v] = defn_type
        return analyse(node.body, new_env, non_generic)
    elif isinstance(node, Letrec):
        new_type = TypeVariable()
        new_env = env.copy()
        new_env[node.v] = new_type
        new_non_generic = non_generic.copy()
        new_non_generic.add(new_type)
        defn_type = analyse(node.defn, new_env, new_non_generic)
        unify(new_type, defn_type)
        return analyse(node.body, new_env, non_generic)
    assert 0, &quot;Unhandled syntax node {0}&quot;.format(type(t))

def getType(name, env, non_generic):
    &quot;&quot;&quot;Get the type of identifier name from the type environment env.

    Args:
        name: The identifier name
        env: The type environment mapping from identifier names to types
        non_generic: A set of non-generic TypeVariables

    Raises:
        ParseError: Raised if name is an undefined symbol in the type
            environment.
    &quot;&quot;&quot;
    if name in env:
        return fresh(env[name], non_generic)
    elif isIntegerLiteral(name):
        return Integer
    else:
        raise ParseError(&quot;Undefined symbol {0}&quot;.format(name))

def fresh(t, non_generic):
    &quot;&quot;&quot;Makes a copy of a type expression.

    The type t is copied. The the generic variables are duplicated and the
    non_generic variables are shared.

    Args:
        t: A type to be copied.
        non_generic: A set of non-generic TypeVariables
    &quot;&quot;&quot;
    mappings = {} # A mapping of TypeVariables to TypeVariables

    def freshrec(tp):
        p = prune(tp)
        if isinstance(p, TypeVariable):
            if isGeneric(p, non_generic):
                if p not in mappings:
                    mappings[p] = TypeVariable()
                return mappings[p]
            else:
                return p
        elif isinstance(p, TypeOperator):
            return TypeOperator(p.name, [freshrec(x) for x in p.types])

    return freshrec(t)

def unify(t1, t2):
    &quot;&quot;&quot;Unify the two types t1 and t2.

    Makes the types t1 and t2 the same.

    Args:
        t1: The first type to be made equivalent
        t2: The second type to be be equivalent

    Returns:
        None

    Raises:
        TypeError: Raised if the types cannot be unified.
    &quot;&quot;&quot;

    a = prune(t1)
    b = prune(t2)
    if isinstance(a, TypeVariable):
        if a != b:
            if occursInType(a, b):
                raise TypeError(&quot;recursive unification&quot;)
            a.instance = b
    elif isinstance(a, TypeOperator) and isinstance(b, TypeVariable):
        unify(b, a)
    elif isinstance(a, TypeOperator) and isinstance(b, TypeOperator):
        if (a.name != b.name or len(a.types) != len(b.types)):
            raise TypeError(&quot;Type mismatch: {0} != {1}&quot;.format(str(a), str(b)))
        for p, q in zip(a.types, b.types):
            unify(p, q)
    else:
        assert 0, &quot;Not unified&quot;

def prune(t):
    &quot;&quot;&quot;Returns the currently defining instance of t.

    As a side effect, collapses the list of type instances. The function Prune
    is used whenever a type expression has to be inspected: it will always
    return a type expression which is either an uninstantiated type variable or
    a type operator; i.e. it will skip instantiated variables, and will
    actually prune them from expressions to remove long chains of instantiated
    variables.

    Args:
        t: The type to be pruned

    Returns:
        An uninstantiated TypeVariable or a TypeOperator
    &quot;&quot;&quot;
    if isinstance(t, TypeVariable):
        if t.instance is not None:
            t.instance = prune(t.instance)
            return t.instance
    return t

def isGeneric(v, non_generic):
    &quot;&quot;&quot;Checks whether a given variable occurs in a list of non-generic variables

    Note that a variables in such a list may be instantiated to a type term,
    in which case the variables contained in the type term are considered
    non-generic.

    Note: Must be called with v pre-pruned

    Args:
        v: The TypeVariable to be tested for genericity
        non_generic: A set of non-generic TypeVariables

    Returns:
        True if v is a generic variable, otherwise False
    &quot;&quot;&quot;
    return not occursIn(v, non_generic)

def occursInType(v, type2):
    &quot;&quot;&quot;Checks whether a type variable occurs in a type expression.

    Note: Must be called with v pre-pruned

    Args:
        v:  The TypeVariable to be tested for
        type2: The type in which to search

    Returns:
        True if v occurs in type2, otherwise False
    &quot;&quot;&quot;
    pruned_type2 = prune(type2)
    if pruned_type2 == v:
        return True
    elif isinstance(pruned_type2, TypeOperator):
        return occursIn(v, pruned_type2.types)
    return False

def occursIn(t, types):
    &quot;&quot;&quot;Checks whether a types variable occurs in any other types.

    Args:
        v:  The TypeVariable to be tested for
        types: The sequence of types in which to search

    Returns:
        True if t occurs in any of types, otherwise False
    &quot;&quot;&quot;
    return any(occursInType(t, t2) for t2 in types)

def isIntegerLiteral(name):
    &quot;&quot;&quot;Checks whether name is an integer literal string.

    Args:
        name: The identifier to check

    Returns:
        True if name is an integer literal, otherwise False
    &quot;&quot;&quot;
    result = True
    try:
        int(name)
    except ValueError:
        result = False
    return result

#==================================================================#
# Example code to exercise the above

def tryExp(env, node):
    &quot;&quot;&quot;Try to evaluate a type printing the result or reporting errors.

    Args:
        env: The type environment in which to evaluate the expression.
        node: The root node of the abstract syntax tree of the expression.

    Returns:
        None
    &quot;&quot;&quot;
    print(str(node) + &quot; : &quot;, end=' ')
    try:
        t = analyse(node, env)
        print(str(t))
    except (ParseError, TypeError) as e:
        print(e)

def main():
    &quot;&quot;&quot;The main example program.

    Sets up some predefined types using the type constructors TypeVariable,
    TypeOperator and Function.  Creates a list of example expressions to be
    evaluated. Evaluates the expressions, printing the type or errors arising
    from each.

    Returns:
        None
    &quot;&quot;&quot;

    var1 = TypeVariable()
    var2 = TypeVariable()
    pair_type = TypeOperator(&quot;*&quot;, (var1, var2))

    var3 = TypeVariable()

    my_env = { &quot;pair&quot; : Function(var1, Function(var2, pair_type)),
               &quot;true&quot; : Bool,
               &quot;cond&quot; : Function(Bool, Function(var3, Function(var3, var3))),
               &quot;zero&quot; : Function(Integer, Bool),
               &quot;pred&quot; : Function(Integer, Integer),
               &quot;times&quot;: Function(Integer, Function(Integer, Integer)) }

    pair = Apply(Apply(Ident(&quot;pair&quot;), Apply(Ident(&quot;f&quot;), Ident(&quot;4&quot;))), Apply(Ident(&quot;f&quot;), Ident(&quot;true&quot;)))

    examples = [
            # factorial
            Letrec(&quot;factorial&quot;, # letrec factorial =
                Lambda(&quot;n&quot;,    # fn n =&gt;
                    Apply(
                        Apply(   # cond (zero n) 1
                            Apply(Ident(&quot;cond&quot;),     # cond (zero n)
                                Apply(Ident(&quot;zero&quot;), Ident(&quot;n&quot;))),
                            Ident(&quot;1&quot;)),
                        Apply(    # times n
                            Apply(Ident(&quot;times&quot;), Ident(&quot;n&quot;)),
                            Apply(Ident(&quot;factorial&quot;),
                                Apply(Ident(&quot;pred&quot;), Ident(&quot;n&quot;)))
                        )
                    )
                ),      # in
                Apply(Ident(&quot;factorial&quot;), Ident(&quot;5&quot;))
            ),

            # Should fail:
            # fn x =&gt; (pair(x(3) (x(true)))
            Lambda(&quot;x&quot;,
                Apply(
                    Apply(Ident(&quot;pair&quot;),
                        Apply(Ident(&quot;x&quot;), Ident(&quot;3&quot;))),
                    Apply(Ident(&quot;x&quot;), Ident(&quot;true&quot;)))),

            # pair(f(3), f(true))
            Apply(
                Apply(Ident(&quot;pair&quot;), Apply(Ident(&quot;f&quot;), Ident(&quot;4&quot;))),
                Apply(Ident(&quot;f&quot;), Ident(&quot;true&quot;))),

            # let f = (fn x =&gt; x) in ((pair (f 4)) (f true))
            Let(&quot;f&quot;, Lambda(&quot;x&quot;, Ident(&quot;x&quot;)), pair),

            # fn f =&gt; f f (fail)
            Lambda(&quot;f&quot;, Apply(Ident(&quot;f&quot;), Ident(&quot;f&quot;))),

            # let g = fn f =&gt; 5 in g g
            Let(&quot;g&quot;,
                Lambda(&quot;f&quot;, Ident(&quot;5&quot;)),
                Apply(Ident(&quot;g&quot;), Ident(&quot;g&quot;))),

            # example that demonstrates generic and non-generic variables:
            # fn g =&gt; let f = fn x =&gt; g in pair (f 3, f true)
            Lambda(&quot;g&quot;,
                   Let(&quot;f&quot;,
                       Lambda(&quot;x&quot;, Ident(&quot;g&quot;)),
                       Apply(
                            Apply(Ident(&quot;pair&quot;),
                                  Apply(Ident(&quot;f&quot;), Ident(&quot;3&quot;))
                            ),
                            Apply(Ident(&quot;f&quot;), Ident(&quot;true&quot;))))),

            # Function composition
            # fn f (fn g (fn arg (f g arg)))
            Lambda(&quot;f&quot;, Lambda(&quot;g&quot;, Lambda(&quot;arg&quot;, Apply(Ident(&quot;g&quot;), Apply(Ident(&quot;f&quot;), Ident(&quot;arg&quot;))))))
    ]

    for example in examples:
        tryExp(my_env, example)

if __name__ == '__main__':
    main()
</pre>
<hr/>Copyright &copy; 2012 <strong><a href="http://www.smallshire.org.uk/sufficientlysmall">Sufficiently Small</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact legal@smallshire.org.uk so we can take legal action immediately.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span>]]></content:encoded>
			<wfw:commentRss>http://www.smallshire.org.uk/sufficientlysmall/2010/04/11/a-hindley-milner-type-inference-implementation-in-python/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Control Flow Graph Linearisation in OWL BASIC</title>
		<link>http://www.smallshire.org.uk/sufficientlysmall/2010/02/14/control-flow-graph-linearisation-in-owl-basic/</link>
		<comments>http://www.smallshire.org.uk/sufficientlysmall/2010/02/14/control-flow-graph-linearisation-in-owl-basic/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 19:27:22 +0000</pubDate>
		<dc:creator>Robert Smallshire</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[OWL BASIC]]></category>
		<category><![CDATA[BBCBASIC]]></category>
		<category><![CDATA[CLR]]></category>

		<guid isPermaLink="false">http://www.smallshire.org.uk/sufficientlysmall/?p=450</guid>
		<description><![CDATA[To compile the code comprising an OWL BASIC procedure, function or main program into CIL, we must linearise the Control Flow Graph (CFG) representing the program statements. The CFG undergoes many transformations during compilation, for example to eliminate unreachable code or convert GOSUB routines into named procedures. Generation of CIL using Reflection.Emit requires that we [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2010%2F02%2F14%2Fcontrol-flow-graph-linearisation-in-owl-basic%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2010%2F02%2F14%2Fcontrol-flow-graph-linearisation-in-owl-basic%2F&amp;source=robsmallshire&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>To compile the code comprising an OWL BASIC procedure, function or main program into CIL, we must linearise the <a href="http://en.wikipedia.org/wiki/Control_flow_graph">Control Flow Graph</a> (CFG) representing the program statements.  The CFG undergoes many transformations during compilation, for example to eliminate unreachable code or convert <code>GOSUB</code> routines into named procedures.  Generation of CIL using Reflection.Emit requires that we can define branch targets in advance of generating branch instructions or marking the target instruction and of course we want to do this in a manner which minimises the number of branches required to represent the code.  The structure of the graph may be quite complex, especially for traditional BASIC spaghetti code which uses GOTO excessively rather than the more structured alternatives such as procedures and functions or the control structures introduced in BBC BASIC V .</p>
<p>Consider the following procedure from Sphinx Adventure.  It contains three loops, one on line 271 formed with a <code>GOTO</code> back to the start of the line, and two <code>REPEAT .. UNTIL</code> loops.</p>
<p>266 DEF PROCL(L)<br />
267 LOCAL I,J:CO=0:CN=0<br />
268 IF L=1 THEN278<br />
269 PRINT&#8217;: RESTORE L: IF O?31&lt;&gt;0 THEN O?31=0:DW=1<br />
270 READ R$,R$:R$=&quot;You are &quot;+R$<br />
271 IF LEN(R$)+ POS&gt;CO-CN+39 THEN R$= FNS(R$,39+CO-CN):CO=CO+39: GOTO271<br />
272 PRINT R$: IFL=136 OR L=15 THEN O?56=L<br />
273 IF L=16 AND FL=1 THEN PRINT&quot;The walls are very hot!&quot; ELSE IF L=16 THEN PRINT &quot;The walls are steaming!&quot;<br />
274 IF L&lt;&gt;3 AND L&lt;&gt;142 AND L&lt;&gt;143 THEN PROCEX(L): IF ABS(L-19)=1 AND CH=1 THEN PRINT ELSE IF ABS(L-42)=1 AND VO=1 THEN PRINT<br />
275 IF CH=1 AND ABS(L-19)=1 THEN PROC R(22): PRINT &quot;chasm.&quot;:O?53=L<br />
276 IF VO=1 AND ABS(L-42)=1 THEN PROCR(22): PRINT&quot;glacier.&quot;:O?53=L<br />
277 IF L=26 OR L=27 THEN O?53=L<br />
278 J=0:I=0:CO=0<br />
279 REPEAT:J=J+1: IF O?J=L  THEN CO=CO+1<br />
280 UNTIL J=52: IF CO=0 AND L=1 THEN PROCR(L): GOTO 284 ELSE IF CO=0 AND L&lt;&gt;1 THEN 284 ELSE PRINT:MAX=CO<br />
281 IF L=1 THEN PROCR(3) ELSE PROCR(4)<br />
282 CN=0:CO=MAX: REPEAT I=I+1: IF O?I=L  THEN PROCOT(I,CO):CO=CO-1<br />
283 UNTIL I=52<br />
284 IF D&lt;&gt;0 THEN O?31=L<br />
285 IF CF=1 AND L=94 THEN PRINT&#8217;&quot;The casket is open.&quot;<br />
286 IF L=24 AND SA=1 THEN PRINT&#8217;&quot;The safe door is open.&quot;<br />
287 PRINT: ENDPROC</p>
<p>The CFG for this code is shown below.  Each program statement is shown as a purple box, with control flow to the following statement(s). Conditionals are shown in diamond boxes.  The numbers in each purple box are source line numbers, where known.</p>
<p>Careful comparison of the source above and the diagram below will reveal some of the transformations that have been applied to the program; for example, <code>READ R$,R$</code> on line 270 has been transformed into two consecutive assignment statements which actually take the form <code>R$ = READ()</code> where <code>READ()</code> is a function not available in the source language.</p>
<p>The <i>statement</i> level CFG has been analysed to identify <a href="http://en.wikipedia.org/wiki/Basic_block">basic-blocks</a>, shown as yellow group nodes, thereby defining a higher level <i>basic-block</i> level CFG.  Each basic block has only one entry point statement; none of the statement within the basic block are destinations of other jump instructions. Furthermore, each block has only one exit point.</p>
<p><i>More text follows this long diagram&#8230;</i></p>
<p><img src="/images/Sphinx_basic_blocks.png" alt="Control Flow Graph for PROC L in Sphinx Adventure" /></p>
<p>Generating the CIL code for a single basic block is straightforward enough &#8211; we can simply iterate through the statements comprising the basic block in order and generate the code for each in turn.  However, there are many possible orders in which the code for the basic block themselves could be representing in the CIL, since we can branch from the end of any block to the next block, although of course we must start at the <i>entry block</i> for the procedure. Although any order starting with the entry block can be made to work, where possible we would like program control to flow smoothly from the end of a block to one of its successors without requiring a branch.</p>
<p>At first sight, some sort of topological ordering would seem to be appropriate, but a topological ordering is only well defined for a <a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph">directed acyclic graph</a> (DAG), and a DAG this program is not.  The key to this conundrum is to reduce the directed graph to a DAG by identifying <a href="http://en.wikipedia.org/wiki/Strongly_connected_components">strongly connected components</a>.  By contracting each SCC to a single node we obtain what is called the <i>condensation</i> of the CFG which <i>will</i> be a DAG. To the resulting DAG we can apply a topological ordering. The ordering of vertices with each SCC is chosen by starting at the vertex with the greatest <a href="http://en.wikipedia.org/wiki/Indegree#Indegree_and_outdegree">in-degree</a>.</p>
<p>In order to identify and contract the SCCs we use an implementation of <a href="http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm">Tarjan&#8217;s algorithm</a> during depth first traversal of the CFG.  The reverse post ordering of the primary depth first traversal is used to generate the topological ordering of the condensed CFG.</p>
<p>The resulting ordering of basic blocks is shown in the diagram by the numeric labels to the top-left of each. This will be the order in which the CIL code for them is generated, and it can be seen that in about half of the cases, fall through from one block to the next (consecutive block numbers) without explicit branching can be exploited.  Future optimisations will focus on further simplifying the generated code by removing vertices, such as block 31, which contain only jumps.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://www.smallshire.org.uk/sufficientlysmall">Sufficiently Small</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact legal@smallshire.org.uk so we can take legal action immediately.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span>]]></content:encoded>
			<wfw:commentRss>http://www.smallshire.org.uk/sufficientlysmall/2010/02/14/control-flow-graph-linearisation-in-owl-basic/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OWL BASIC produces its first executable</title>
		<link>http://www.smallshire.org.uk/sufficientlysmall/2009/08/04/owl-basic-produces-its-first-executable/</link>
		<comments>http://www.smallshire.org.uk/sufficientlysmall/2009/08/04/owl-basic-produces-its-first-executable/#comments</comments>
		<pubDate>Tue, 04 Aug 2009 21:45:26 +0000</pubDate>
		<dc:creator>Robert Smallshire</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[IronPython]]></category>
		<category><![CDATA[OWL BASIC]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.smallshire.org.uk/sufficientlysmall/?p=394</guid>
		<description><![CDATA[After a long haul, and diversions into other more important projects &#8212; including starting a family &#8212; OWL BASIC today produced its first executable. Its not much. In fact its hardly anything. Just 2048 bytes of Windows PE executable containing the global variable declarations from Acornsoft&#8217;s 1982 Sphinx Adventure. Each file of BASIC source code [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2009%2F08%2F04%2Fowl-basic-produces-its-first-executable%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2009%2F08%2F04%2Fowl-basic-produces-its-first-executable%2F&amp;source=robsmallshire&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>After a long haul, and diversions into other more important projects &#8212; including starting a family &#8212; <a href="http://www.smallshire.org.uk/sufficientlysmall/2007/06/10/writing-a-bbc-basic-compiler-for-the-clr/">OWL BASIC</a> today produced its first executable.  Its not much. In fact its hardly anything. Just 2048 bytes of Windows PE executable containing the global variable declarations from Acornsoft&#8217;s 1982 Sphinx Adventure. Each file of BASIC source code will be converted to a single .NET static class, with the global variables as private static fields.</p>
<div id="attachment_395" class="wp-caption aligncenter" style="width: 538px"><img src="http://www.smallshire.org.uk/sufficientlysmall/wp-content/uploads/sphinx_reflector.png" alt="The first executable produced from OWL BASIC." title="sphinx_reflector" width="528" height="571" class="size-full wp-image-395" /><p class="wp-caption-text">The first executable produced from OWL BASIC.</p></div>
<p>Above you can see the executable loaded up into <a href="http://www.red-gate.com/products/reflector/">.NET Reflector</a>, which can be used to introspect the executable, and in this case attempt to disassemble it into C#.  Now we see what makes .NET such a great platform for compiler construction; below is the <a href="http://www.codeplex.com/IronPython">IronPython</a> source code for the embryonic assembly generation function. It clocks in at fewer than ten lines of code to create an assembly, create a module, create a class, add one private static field to it for each global variable, and save the result as an <code>.exe</code>.</p>
<pre class="brush: python; title: ; notranslate">
def generateAssembly(name, global_symbols):
    domain = Thread.GetDomain()
    assembly_name = AssemblyName(name)
    assembly_builder = domain.DefineDynamicAssembly(assembly_name, AssemblyBuilderAccess.RunAndSave)
    module_builder = assembly_builder.DefineDynamicModule(name + &quot;.exe&quot;)
    type_builder = module_builder.DefineType(name, TypeAttributes.Class | TypeAttributes.Public, object().GetType())

    # Add global variables to the class
    for symbol in global_symbols.symbols.values():
        field_builder = type_builder.DefineField(symbol.name, ctsType(symbol),
                                                 FieldAttributes.Private | FieldAttributes.Static)

    result = type_builder.CreateType()
    assembly_builder.Save(name + &quot;.exe&quot;)
</pre>
<p>where <code>global_symbols</code> is the global symbol table constructed during traversal of the Abstract Syntax Tree and the Control Flow Graph and the <code>ctsType</code> function maps OWL BASIC types to their equivalent <a href="http://en.wikipedia.org/wiki/Common_Type_System">Common Type System</a> types for .NET.  Everything else is provided by <a href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.aspx">Reflection.Emit</a> and other parts of .NET.</p>
<p>Its interesting that no validation was applied to the variable names supplied to <code>Reflection.Emit</code>.  As you can see, the variable names still include the <a href="http://en.wikipedia.org/wiki/Sigil_(computer_programming)">sigil</a> suffixes for variable typing (<i>e.g.</i> $ for string) and Reflector happily dissassembles these into invalid C# identifiers.  For the final version these names will need to be mangled (<a href="http://en.wikipedia.org/wiki/Hungarian_notation">Hungarian notation</a>?), or merely de-sigiled if no conflicts result, for compatibility with other .NET languages and tools.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://www.smallshire.org.uk/sufficientlysmall">Sufficiently Small</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact legal@smallshire.org.uk so we can take legal action immediately.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span>]]></content:encoded>
			<wfw:commentRss>http://www.smallshire.org.uk/sufficientlysmall/2009/08/04/owl-basic-produces-its-first-executable/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>IronPython hammers CPython when not mutating class attributes</title>
		<link>http://www.smallshire.org.uk/sufficientlysmall/2009/05/22/ironpython-hammers-cpython-when-not-mutating-class-attributes/</link>
		<comments>http://www.smallshire.org.uk/sufficientlysmall/2009/05/22/ironpython-hammers-cpython-when-not-mutating-class-attributes/#comments</comments>
		<pubDate>Fri, 22 May 2009 18:52:58 +0000</pubDate>
		<dc:creator>Robert Smallshire</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[IronPython]]></category>
		<category><![CDATA[Jython]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.smallshire.org.uk/sufficientlysmall/?p=171</guid>
		<description><![CDATA[Earlier today I posted the second article in what is turning out to be a short series in the investigation into why the performance of IronPython is around 100× slower than CPython, when running the front-end of my OWL BASIC compiler. The most informative comment was from Curt Hagenlocher who works on IronPython in the [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2009%2F05%2F22%2Fironpython-hammers-cpython-when-not-mutating-class-attributes%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2009%2F05%2F22%2Fironpython-hammers-cpython-when-not-mutating-class-attributes%2F&amp;source=robsmallshire&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Earlier today I posted the <a href="http://www.smallshire.org.uk/sufficientlysmall/2009/05/22/ironpython-2-0-and-jython-2-5-performance-compared-to-python-2-5/">second article</a> in what is turning out to be a short series in the investigation into why the performance of IronPython is around 100× slower than CPython, when running the front-end of my OWL BASIC compiler.</p>
<p>The most informative <a href="http://www.smallshire.org.uk/sufficientlysmall/2009/05/22/ironpython-2-0-and-jython-2-5-performance-compared-to-python-2-5/#comment-2071">comment</a> was from <a href="http://blogs.msdn.com/curth/">Curt Hagenlocher</a> who works on IronPython in the Visual Studio Managed Languages group at Microsoft.</p>
<p>Curt suggested,</p>
<blockquote><p>
Try storing the counter as a global variable instead of a class-level member of Node — I think you’ll notice a dramatic improvement.
</p></blockquote>
<p>The modified benchmark program looks like this:</p>
<pre class="brush: python; title: ; notranslate">
counter = 0

class Node(object):

    def __init__(self, children):
        global counter
        counter += 1
        self._children = children

def make_tree(depth):
    if depth &gt; 1:
        return Node ([make_tree(depth - 1), make_tree(depth - 1)])
    else:
        return Node([])

def main(argv=None):
    global counter
    if argv is None:
        argv = sys.argv
    depth = int(argv[1]) if len(argv) &gt; 1 else 10

    root = make_tree(depth)
    print counter
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main())
</pre>
<h2>A dramatic improvement!</h2>
<p>Well, Curt wasn&#8217;t wrong. This made a phenomenal difference with IronPython completing in only 12% of the time taken by CPython &#8211; over 8× <em>faster</em> with a binary tree depth of 20.</p>
<p>Let&#8217;s look in detail at the results.  All results are from a dual quad-core 1.86 GHz Xeon with 4 GB RAM, and as before each benchmark was run five times, and the shortest time of the five taken.</p>
<p>The three test environments are:</p>
<ol>
<li>Python 2.5.2 x86 32-bit</li>
<li>Jython 2.5rc2 on Java Hotspot 1.6 32-bit</li>
<li>IronPython 2.0 on .NET 2.0 x64</li>
</ol>
<div class="wp-caption alignnone" style="width: 610px"><img alt="The relative performance of the three main Python implementations on a benchmark that uses a global counter, rather than mutating a class attribute." src="/sufficientlysmall/wp-content/ipy_performance/tree_x64_inclusive_global.png" title="The relative performance of the three main Python implementations" width="600" height="450" /><p class="wp-caption-text">Figure 1. The relative performance of the three main Python implementations on a benchmark that uses a global counter, rather than mutating a class attribute.</p></div>
<p>Here we can see how IronPython&#8217;s performance has been improved hugely by this simple change. Although startup time dominates for the smaller problem size, now both Jython <em>and</em> IronPython surpass CPython at around half-a-million nodes.</p>
<p>Removing start-up time, which may be irrelevant for long-running processes, gives us the following chart:</p>
<div class="wp-caption alignnone" style="width: 610px"><img alt="The performance of the three main Python implementations excluding start-up time." src="/sufficientlysmall/wp-content/ipy_performance/tree_x64_exclusive_global.png" title="The performance of the three main Python implementations excluding start-up time." width="600" height="450" /><p class="wp-caption-text">Figure 2. The performance of the three main Python implementations excluding start-up time.</p></div>
<p>Again there is a lot of noise in the data below 1000 nodes, but it is clear that Jython scales better than IronPython, which in turn is scaling better than CPython.</p>
<p>Up until now I&#8217;ve been using a log-log scale in the charts because of the wide variation in performance between the different implementations, but now the performance gap is much closer, it&#8217;s difficult to get a sense of just how <i>much</i> faster IronPython is on the modified benchmark.  Let&#8217;s throw in a log-linear plot to help us appreciate what&#8217;s going on:</p>
<div class="wp-caption alignnone" style="width: 610px"><img alt="Figure 3. A linear representation of the same data as in Figure 2, to highlight the performance multiple between IronPython and CPython in the larger tests." src="/sufficientlysmall/wp-content/ipy_performance/tree_x64_linear_global.png" title="A linear representation of the same data as in Figure 2, to highlight the performance multiple between IronPython and CPython in the larger tests." width="600" height="450" /><p class="wp-caption-text">Figure 3. A linear representation of the same data as in Figure 2, to highlight the performance multiple between IronPython and CPython in the larger tests.</p></div>
<p>It&#8217;s perhaps easier to see now that IronPython is doing in 14 seconds what takes CPython 114 seconds to achieve!</p>
<p>Finally, let&#8217;s plot those results as we did before, as multiples of CPython performance:</p>
<div class="wp-caption alignnone" style="width: 610px"><img alt="Figure 4. Execution time of Jython and IronPython as multiples of CPython performance." src="/sufficientlysmall/wp-content/ipy_performance/tree_x64_relative_global.png" title="Figure 4. Execution time of Jython and IronPython as multiples of CPython performance." width="600" height="450" /><p class="wp-caption-text">Figure 4. Execution time of Jython and IronPython as multiples of CPython performance.</p></div>
<p>It is easy to see that in this chart, once we pass half-a-million tree nodes (a tree depth of 19) that both Jython and IronPython are significantly beating CPython.</p>
<h2>Explanation</h2>
<p>Curt Hagenlocher offers the explanation in a <a href="http://www.reddit.com/r/programming/comments/8mfh7/terrible_ironpython_20_and_pretty_good_jython_25/c09r51x">comment</a> in the <a href="http://www.reddit.com/r/programming/comments/8mfh7/terrible_ironpython_20_and_pretty_good_jython_25/">thread </a> on <a href="http://www.reddit.com">Reddit</a>.</p>
<blockquote><p>
In this particular case, IronPython is slow because of the update to Node.counter. Currently, any update to a class will increment the version number for the class, which will have the effect of invalidating any rules compiled for that class. Effectively, the same rules are getting compiled over and over again. Moving the counter to a global should result in performance on par with that of CPython.
</p></blockquote>
<p>which is absolutely correct, except that he&#8217;s underselling the relative gain. IronPython is not only on a par with CPython, it can outperform it by a factor of eight!</p>
<p>With this knowledge in hand, I can now approach optimization of my OWL BASIC compiler, which lies back at the start of this illuminating tale.</p>
<h2>Conclusion</h2>
<ul>
<li>Avoiding mutation of Python class attributes can have significant benefits for IronPython performance.</li>
<li>Both IronPython and Jython scale better than CPython by this benchmark, and have superior performance for large trees of nodes.</li>
</ul>
<hr/>Copyright &copy; 2012 <strong><a href="http://www.smallshire.org.uk/sufficientlysmall">Sufficiently Small</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact legal@smallshire.org.uk so we can take legal action immediately.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span>]]></content:encoded>
			<wfw:commentRss>http://www.smallshire.org.uk/sufficientlysmall/2009/05/22/ironpython-hammers-cpython-when-not-mutating-class-attributes/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>IronPython 2.0 and Jython 2.5 performance compared to Python 2.5</title>
		<link>http://www.smallshire.org.uk/sufficientlysmall/2009/05/22/ironpython-2-0-and-jython-2-5-performance-compared-to-python-2-5/</link>
		<comments>http://www.smallshire.org.uk/sufficientlysmall/2009/05/22/ironpython-2-0-and-jython-2-5-performance-compared-to-python-2-5/#comments</comments>
		<pubDate>Fri, 22 May 2009 11:34:28 +0000</pubDate>
		<dc:creator>Robert Smallshire</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[IronPython]]></category>
		<category><![CDATA[Jython]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[BBCBASIC]]></category>
		<category><![CDATA[CLR]]></category>
		<category><![CDATA[dotNET]]></category>

		<guid isPermaLink="false">http://www.smallshire.org.uk/sufficientlysmall/?p=118</guid>
		<description><![CDATA[IronPython 2.0 can be hundreds of times slower than CPython on some microbenchmarks.  Jython 2.5 can scale better than CPython on those same benchmarks.]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2009%2F05%2F22%2Fironpython-2-0-and-jython-2-5-performance-compared-to-python-2-5%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2009%2F05%2F22%2Fironpython-2-0-and-jython-2-5-performance-compared-to-python-2-5%2F&amp;source=robsmallshire&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>My <a href="http://www.smallshire.org.uk/sufficientlysmall/2009/05/17/the-performance-of-python-jython-and-ironpython/">previous post</a> covering the performance problems I&#8217;ve been experiencing with IronPython raised some questions about whether the low performance was an effect peculiar to my system, or to my program &#8212; the <a href="http://www.smallshire.org.uk/sufficientlysmall/2007/06/10/writing-a-bbc-basic-compiler-for-the-clr/">OWL BASIC</a> compiler &#8212; where the problem was first noticed. To briefly recap, I&#8217;d determined that IronPython was around 100× slower that CPython on the same program.</p>
<p>Since then, I&#8217;ve had time to reproduce the results with a small and completely unremarkable Python program, and also to run the tests on a different system. I had suspected that in the OWL BASIC compiler, my Python visitor implementation, which is used in applying transformations to the abstract syntax tree, was to blame. I set about condensing a tree visitor down to a small example, but I never got that far.  It is sufficient to simply <i>build</i> a large binary tree to demonstrate the dramatic differences in the performance characteristics of the three main Python implementations.</p>
<h2>The benchmark</h2>
<p>Here is that test program, which just builds a simple binary tree of objects to the requested depth.</p>
<pre class="brush: python; title: ; notranslate">
class Node(object):
    counter = 0

    def __init__(self, children):
        Node.counter += 1
        self._children = children

def make_tree(depth):
    if depth &gt; 1:
        return Node ([make_tree(depth - 1), make_tree(depth - 1)])
    else:
        return Node([])

def main(argv=None):
    if argv is None:
        argv = sys.argv
    depth = int(argv[1]) if len(argv) &gt; 1 else 10

    root = make_tree(depth)
    print Node.counter
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main())
</pre>
<p>The program builds a binary tree to the depth supplied as the only command line argument, or ten if one is not supplied. It counts the number of nodes as they a built. Remember that the merits or otherwise of this program are not the point! The point is the performance difference between the Python implementations when it is run.</p>
<p>My benchmarking approach has been to run this script five times for each tree depth from a depth of one, upwards to 22, or until my patience was exhausted.  I&#8217;ve taken the minimum time from each run of five. Since there is a non-linear relationship between the depth of the tree and the number of nodes contained therein, logarithmic axes are used in all the charts that follow.</p>
<h2>64 bit Windows Vista x64</h2>
<p>Here are the results for the first test machine &#8211; with dual quad-core 1.86 GHz Xeons with 4 GB RAM running Vista x64, testing IronPython 2.0.0.0 on .NET 2.0, Jython 2.5rc2 on Java Hotspot 1.6.0 and Python 2.5.2.</p>
<div class="wp-caption alignnone" style="width: 610px"><img alt="Create time for a binary tree including Python virtual machine startup on Windows Vista x64 with 1.86 GHz Xeon processors." src="/sufficientlysmall/wp-content/ipy_performance/tree_x64_inclusive.png" title="Binary tree creation on x64" width="600" height="450" /><p class="wp-caption-text">Figure 1. Creation time for a binary tree including Python virtual machine startup on Windows Vista x64 with 1.86 GHz Xeon processors.</p></div>
<p>In Figure 1 we see that above 1000 nodes or so (tree depth of 10) performance for IronPython begin to degrade rapidly. CPython holds out for another two orders of magnitude before the significant costs begin to be felt . Its interesting to see that although Jython is in the middle of the pack, it scales much better than CPython, surpassing it at around half-a-million nodes (tree depth of 19).</p>
<p>In my application &#8212; a compiler &#8212; virtual machine (VM) start-up time is important; however, in many long-running applications this is not the case, so it is interesting to subtract VM start-up time from each series, which we see in Figure 2, below.</p>
<div class="wp-caption alignnone" style="width: 610px"><img alt="By subtracting VM start-up time, we get a picture more interesting for long-running processes." src="/sufficientlysmall/wp-content/ipy_performance/tree_x64_exclusive.png" title="Execution time excluding VM start-up, on Vista x64 with 1.87 GHz Xeon processors" width="600" height="450" /><p class="wp-caption-text">By subtracting VM start-up time, we get a picture more interesting for long-running processes.</p></div>
<p>Below 100 tree nodes, there is a lot of noise in these measurements. Above 100 nodes its easy to see that the blue IronPython curve is at least two chart divisions above the red CPython curve &#8212; that&#8217;s two orders of magnitude or 100× slower, and getting relatively worse as the size of the tree increases.</p>
<h2>32 bit Windows XP x86</h2>
<p>Responses to my earlier article suggested that trying IronPython 2.0.1 with Ngen&#8217;ed binaries on x86 may make a difference.  Well, to cut a long story short, it doesn&#8217;t, but here are the details.   These tests were run on a 900 MHz Pentium M Centrino laptop with 768 MB RAM, and so cannot be directly compared with those above, although its notable that a one year old workstation is only twice as fast as a five year old laptop.  Moore&#8217;s law certainly isn&#8217;t delivering here!</p>
<div class="wp-caption alignnone" style="width: 610px"><img alt="The performance profiles are very similar with IronPython 2.0.1 on x86." src="/sufficientlysmall/wp-content/ipy_performance/tree_x86_exclusive.png" title="Performance for building a binary tree on a 900 MHz Pentium M." width="600" height="450" /><p class="wp-caption-text">The performance profiles are very simular with IronPython 2.0.1 on x86.</p></div>
<p>On x86, IronPython is still 100× slower than CPython, and Jython still scales better.  It seems the essence of this benchmark is not dependent on which hardware or CLR platform it is run.</p>
<p>I&#8217;ll close by re-presenting the data in the x86 benchmarks as multiples of CPython performance, because it dramatically demonstrates the different responses to the scale of the problem size for IronPython and Jython. Again we see Jython catching up with CPython at a tree depth of 19, just we saw on x64. and IronPython delivering 6000× worse than CPython at a tree depth depth of 15. A tree of this size with thirty-thousand nodes is very similar in scale to the AST tree sizes found in the OWL BASIC during compilation of large programs.</p>
<div class="wp-caption alignnone" style="width: 610px"><img alt="Performance of IronPython and Jython as multiples of CPython performance." src="/sufficientlysmall/wp-content/ipy_performance/tree_x86_relative.png" title="Performance of IronPython and Jython as multiples of CPython performance." width="600" height="450" /><p class="wp-caption-text">Performance of IronPython and Jython as multiples of CPython performance.</p></div>
<h2>Conclusions</h2>
<ul>
<li>
IronPython can be <strong>very</strong> slow, even on programs in the microbenchmark category, which are doing standard operations such as building trees. Presumably there are still significant optimizations to be made in IronPython to bring its performance closer to that of the other Python implementations.  Hopefully, this example and the measurements can contribute to that improvement.
</li>
<li>
Jython may scale better than Python if your application exercises Python in similar ways to this benchmark.  Speculatively, that <i>could</i> have implications for projects such as <a href="http://www.scons.org/">SCons</a>, which build large in-memory graphs.
</li>
<li>I suppose if nothing else we have demonstrated in passing that Java <i>can</i> be faster than C for some non-trivial programs (like a Python interpreter) running a trivial program, like this benchmark.</li>
</ul>
<hr/>Copyright &copy; 2012 <strong><a href="http://www.smallshire.org.uk/sufficientlysmall">Sufficiently Small</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact legal@smallshire.org.uk so we can take legal action immediately.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span>]]></content:encoded>
			<wfw:commentRss>http://www.smallshire.org.uk/sufficientlysmall/2009/05/22/ironpython-2-0-and-jython-2-5-performance-compared-to-python-2-5/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>Dismal performance with IronPython</title>
		<link>http://www.smallshire.org.uk/sufficientlysmall/2009/05/17/the-performance-of-python-jython-and-ironpython/</link>
		<comments>http://www.smallshire.org.uk/sufficientlysmall/2009/05/17/the-performance-of-python-jython-and-ironpython/#comments</comments>
		<pubDate>Sun, 17 May 2009 20:56:46 +0000</pubDate>
		<dc:creator>Robert Smallshire</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[Jython]]></category>
		<category><![CDATA[OWL BASIC]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[IronPython CLR dotNET BBCBASIC]]></category>

		<guid isPermaLink="false">http://www.smallshire.org.uk/sufficientlysmall/?p=63</guid>
		<description><![CDATA[IronPython can be slow - 10x to 100x slower than CPython on real-world code and it has been observed to be up to 6000x slower.]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2009%2F05%2F17%2Fthe-performance-of-python-jython-and-ironpython%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2009%2F05%2F17%2Fthe-performance-of-python-jython-and-ironpython%2F&amp;source=robsmallshire&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Significant claims have been made about the performance of <a href="http://ironpython.codeplex.com/">IronPython</a>, notably back at its inception in 2004 when Jim Hugunin, creator of both IronPython and its cousin <a href="http://www.jython.org/">Jython</a>, presented a <a href="http://www.python.org/community/pycon/dc2004/papers/9/">paper</a> on IronPython performance at PyCon. Since then, there have been numerous claims to IronPython&#8217;s supremacy over CPython in the performance stakes. The <a href="http://www.codeplex.com/IronPython/Wiki/View.aspx?title=IP20VsCPy25Perf&#038;referringTitle=IronPython%20Performance">IronPython Performance Report</a>  reiterates that IronPython can turn in a good performance. According to Hugenin the standard line we&#8217;ll see is,</p>
<blockquote><p>
&#8220;IronPython is fast &#8211; up to 1.8x faster than CPython on the standard pystone benchmark.
</p></blockquote>
<p>But do these claims stand up in the face of real-world Python code?</p>
<p>The claims of good performance are based on synthetic micro-benchmarks which don&#8217;t accurately reflect balance of coding techniques found in complete programs.  </p>
<p>At this point I&#8217;d like to offer my own quote:</p>
<blockquote><p>
&#8220;IronPython can be slow &#8211; 10x to 100x slower than CPython on real-world code and it has been observed to be up to 6000x slower.
</p></blockquote>
<p>Now, the unfortunate thing about real-world code is that it hasn&#8217;t been hand-crafted to highlight the performance characteristics of some aspect of the language implementation like your typical micro-benchmark. Its been written, most likely without any attention to performance. This is especially in the case of a prototype, as in my case.</p>
<h2>Is my code really that bad?</h2>
<p>Over the past few years I&#8217;ve been working on a hobby project called <a href="http://www.smallshire.org.uk/sufficientlysmall/2007/06/10/writing-a-bbc-basic-compiler-for-the-clr/">OWL BASIC</a>, which is a compiler for the BBC BASIC lanaguage targeting the .NET Common Language Runtime (CLR).  At the outset of the project I decided to write the compiler itself in Python, for much the same reasons as <a href="http://codespeak.net/pypy/dist/pypy/doc/">PyPy</a> is written in Python &#8212; hackability. I planned specifically to use IronPython so I could benefit from access to useful .NET libraries such a <code>Reflection.Emit</code>, for generating Common Intermediate Language (CIL) assemblies.</p>
<p>During the course of developing OWL BASIC, as the code has become more complex, I&#8217;ve been consitently disappointed by the negative delta between the promise and reality of IronPython&#8217;s performance. The poor performance of IronPython has negated, for me, one of the main advantages of developing in Python &#8212; the rapid edit-run cycle.</p>
<p>Was my code really so inefficient?  Performance was never a goal of the project, but the underwhelming performance has threatened the viability of my approach and made me question the wisdom of my chosen route of writing a compiler in Python.</p>
<p>The absence of profiling tools for IronPython led me down the road of getting at least the compiler front-end to work on CPython, so I could use the standard Python profilers. Fortunately, my code was portable (its just regular Python) and so I determined that with a few inconsequential tweaks to my code, the entire compiler front-end can be run on the trinity of CPython, Jython and IronPython.</p>
<p>I was, to say the least, somewhat surprised by the results.</p>
<h2>The evidence: performance of CPython, Jython and IronPython</h2>
<p>The investigation into the relative performance of the three main Python implementations was centered on running my unmodified, unprofiled and unoptimized compiler front-end on third-party BBC BASIC source-code (Acornsoft Sphinx Adventure) and measuring the execution time.  All tests runs were performed five times, and the minimum time of the five chosen. Variance between the readings on successive runs was small.  The following Python implementations were on the test-bench:</p>
<ul>
<li>Python 2.5.1 (x86)</li>
<li>Jython 2.5rc2 on Java HotSpot 1.6.0_10-rc</li>
<li>IronPython 2.0 on .NET 2.0 (x64)</li>
</ul>
<p>All tests were run on a eight-core 1.86 GHz Xeon with 4 GB RAM running Vista Ultimate x64.</p>
<p>The following chart shows the results of running the compiler over the source code for Sphinx Adventure.</p>
<div class="wp-caption alignnone" style="width: 610px"><img alt="ipy_performance/absolute_performance.png" src="/sufficientlysmall/wp-content/ipy_performance/absolute_performance.png" title="Execution time of OWL BASIC compiler front-end" width="600" height="225" /><p class="wp-caption-text">The absolute performance of CPython, Jython and IronPython on my code</p></div>
<p>Frankly, I was astounded.  IronPython was left in the dust, not only by CPython but also Jython!  Overall, CPython was 93× faster on the exact same code.  The IronPython hyperbole, for now I could see that was what is was, had led to me expect numbers similar to those for CPython, although I had perhaps more realistic expectations that performance would be similar to Jython. </p>
<p>At this point I assumed I&#8217;d hit some corner case in which IronPython was performing relatively badly.  I&#8217;d had a similar experience early on in the project with code from the PLY parsing package causing IronPython 1.1 to perform badly, but I&#8217;d worked around the issue by modifying parts of PLY to use pickling rather than eval-ing large list literals for the cached parsing tables. [Its worth noting in passing that this problem still exists with the IronPython and PLY combination - I'll publish my solution in another post].</p>
<p>I decided to dig in a little more detail and collect some timing data on the sequence of top level calls the compiler front-end makes to parse the source code followed by a sequence of transformations to the abstract syntax tree (AST). The chart below shows these top level calls, in the order in which the occur during compilation:</p>
<div class="wp-caption alignnone" style="width: 610px"><img alt="ipy_performance/performance_ratio.png" src="/sufficientlysmall/wp-content/ipy_performance/performance_ratio.png" title="The ratio of performance of CPython to both IronPython and Jython when running the OWL BASIC compiler" width="600" /><p class="wp-caption-text">The ratio of performance of CPython to both IronPython and Jython when running the OWL BASIC compiler</p></div>
<p>As you can see, I have had to resort to a logarithmic scale in order to convey the huge variation in the performance of IronPython relative to CPython, ranging from buildParser with a multiple of 3.8 to convertSubroutinesToProcedures with a multiple of over 6400.  Even if we ignore this outlier (maybe we are suffering from a garbage collection &#8211; but notice that Jython is also relatively much slower on this function) we can see that Jython is typically 5× to 10× slower than CPython whereas IronPython is typically 10× to 100× slower than CPython.</p>
<p>Notice also that there is a marked decline in the performance of IronPython from the parse function onwards; the common factor in these operations are that they are all transformations to the AST, and my AST node classes are instantiated by a Python metaclass, although its pure speculation on my part that metaclasses are the cause of this performance drop.</p>
<h2>Conclusion</h2>
<p>On my program at least, Jython is 6× slower than CPython and IronPython is nearly 100× slower.   If you&#8217;re suffering from poor performance with IronPython, it may be well worth your time checking performance of your code on the other Python implementations, if that is an option for you.</p>
<p>Now need to find the root cause and boil my problem down to a short example which can form the basis of a bug report to the IronPython team.  Given that the problem is pervasive in my code, that won&#8217;t be hard.</p>
<p>See you at EuroPython 2009 !</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://www.smallshire.org.uk/sufficientlysmall">Sufficiently Small</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact legal@smallshire.org.uk so we can take legal action immediately.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span>]]></content:encoded>
			<wfw:commentRss>http://www.smallshire.org.uk/sufficientlysmall/2009/05/17/the-performance-of-python-jython-and-ironpython/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>OWL BASIC runtime library takes shape</title>
		<link>http://www.smallshire.org.uk/sufficientlysmall/2009/02/11/owl-basic-runtime-library-takes-shape/</link>
		<comments>http://www.smallshire.org.uk/sufficientlysmall/2009/02/11/owl-basic-runtime-library-takes-shape/#comments</comments>
		<pubDate>Wed, 11 Feb 2009 22:25:55 +0000</pubDate>
		<dc:creator>Robert Smallshire</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[OWL BASIC]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.smallshire.org.uk/sufficientlysmall/2009/02/11/owl-basic-runtime-library-takes-shape/</guid>
		<description><![CDATA[For a useful re-implementation of BBC BASIC, especially in compiled form, a run-time system is needed to provide services to the running program which cannot be directly provided by the operating system. In the case of our OWL BASIC implementation, we are targeting .NET so we already have a very sophisticated run-time in the shape [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2009%2F02%2F11%2Fowl-basic-runtime-library-takes-shape%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2009%2F02%2F11%2Fowl-basic-runtime-library-takes-shape%2F&amp;source=robsmallshire&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>For a useful re-implementation of BBC BASIC, especially in compiled form, a run-time system is needed to provide services to the running program which cannot be directly provided by the operating system.  In the case of our OWL BASIC implementation, we are targeting .NET so we already have a very sophisticated run-time in the shape of the CLR (Common Language Runtime). Nevertheless, additional services specific to the BBC BASIC language are required, many of them based closely on old Acorn hardware from the BBC Micro and RISC OS eras.  Fortunately, many of the services required to produce a functioning BBC BASIC system are fairly well abstracted from hardware details, as the many different implementations on quite different underlying hardware, such as BBC BASIC for Windows, have shown.</p>
<p>Many of the services, such as the VDU drivers, used extensively by BBC BASIC are not strictly part of the language; however, a fairly complete implementation is required in order that existing programs can be run successfully with little or no modification.</p>
<p>Its difficult to know where to draw the line when deciding on the degree of backwards compatibility. Our aim is to get the most widely used features to work well. Some of the obscure features may never be implemented.  We must also strike a balance between .NET compatibility and good interoperability with other .NET languages and tools, and what I will call Acorn compatibility, for want of a better term.</p>
<h1>Implementation details</h1>
<p>Our OWL Runtime Library (ORL) is coding in C# and leans heavily on the existing .NET framework.  We plan to support common RISCOS SWI calls and a fairly complete VDU system.  Much of the work by my brother Ian and myself has to date has focussed on the VDU system, which uses GDI+ through the System.Drawing2D namespace of .NET to do most of the heavy lifting.</p>
<h1>Compatibility Testing</h1>
<p>The testing approach has been as follows:</p>
<ol>
<li>Find write a simple but interesting BBC BASIC program using graphics commands, such as GCOL, <code>MOVE</code>, <code>PLOT</code> and <code>VDU</code>. Execute this program on Acorn hardware or an emulator to get the graphics output.</li>
<li>Convert all graphics commands to their equivalent VDU sequences. For example <code>GCOL 0, 3</code> becomes <code>VDU 18, 0, 3</code>, and verify that program output is the same</li>
<li>Write a test in C# against our OWL Runtime Library using the VDU codes, and very that output is sufficienly similar.</li>
<li>Compile and run the original BBC BASIC test program using the OWL BASIC compiler and verify the output</li>
</ol>
<p>Currently we are pursuing steps 1-3 above as the compiler is not yet ready for step 4. This enables us to work on the run-time library and compiler concurrently.</p>
<h1>Example program</h1>
<p>The following is a fragment from a larger example program.</p>
<p>REM BBC BASIC using graphics commands<br />
size% = 220<br />
radius% = 250<br />
FOR t% = 1 TO 4<br />
    radius -= 30<br />
    c% = 3<br />
    cntr% = 0<br />
    cd% = 0<br />
    FOR x2% = 100 TO 450 STEP 20<br />
        cntr% += 1<br />
        GCOL 0, (c% AND 63)<br />
        TINT 2, (t% &#8211; 1) * 64<br />
        MOVE size, size<br />
        MOVE size + (COS(RAD(x2% &#8211; 20)) * radius%), size% + (SIN(RAD(x2% &#8211; 20)) * radius%)<br />
        PLOT 85, size + (COS(RAD(x2%)) * radius%), size% + (SIN(RAD(x2%)) * radius%)<br />
        CASE cntr% OF<br />
            WHEN 1:  cd% = 4<br />
            WHEN 4:  cd% = -1<br />
            WHEN 7:  cd% = 16<br />
            WHEN 10: cd% = -4<br />
            WHEN 13: cd% = 1<br />
            WHEN 16: cd% = -16<br />
        ENDCASE<br />
        c% += cd%<br />
    NEXT<br />
NEXT</p>
<p>which can be converted to the equivalent program which uses only VDU commands:</p>
<p>size% = 220<br />
radius% = 250<br />
FOR t% = 1 TO 4<br />
    radius -= 30<br />
    c% = 3<br />
    cntr% = 0<br />
    cd% = 0<br />
    FOR x2% = 100 TO 450 STEP 20<br />
        cntr% += 1<br />
            VDU 18,0,(C AND 63)<br />
            VDU 23, 17, 2, (T &#8211; 1) * 64, 0,0,0,0,0,0<br />
            VDU 25, 4, size%; size%;<br />
            VDU 25, 4, size% + (COS(RAD(x2% &#8211; 20)) * radius%); size% + (SIN(RAD(x2% &#8211; 20)) * radius%);<br />
            VDU 25, 85,  size + (COS(RAD(x2%)) * radius%);  size% + (SIN(RAD(x2%)) * radius%);<br />
        CASE cntr% OF<br />
            WHEN 1:  cd% = 4<br />
            WHEN 4:  cd% = -1<br />
            WHEN 7:  cd% = 16<br />
            WHEN 10: cd% = -4<br />
            WHEN 13: cd% = 1<br />
            WHEN 16: cd% = -16<br />
        ENDCASE<br />
        c% += cd%<br />
    NEXT<br />
NEXT</p>
<p>These programs both give the following output in Arculator :</p>
<p><img src="http://www.smallshire.org.uk/sufficientlysmall/wp-content/wheel.png" alt="Colour wheel display in Arculator" /></p>
<p>Translating the second version above into C# against our run time library, we get the following:</p>
<pre class="brush: csharp; title: ; notranslate">
const short size = 220;
int radius = 250;

for (int t = 1; t &lt; 5; ++t)
{
    radius -= 30;
    int c = 3;
    int cntr = 0;
    int cd = 0;

    for (int circle = 100; circle &lt; 450; circle+=20)
    {
        cntr++;
        // TINT action (2) color (t * 64)
        vdu.Enqueue((byte)23, (byte)17, (byte)2, (byte)((t-1) *64));
        vdu.Enqueue((byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0);

        // GCOL action (0) color (c &amp; 63)
        vdu.Enqueue((byte)18, (byte)0, (byte)(c &amp; 63));

        short mov1x = (short)(size + (Math.Cos((circle - 20) * (Math.PI / 180)) * radius));
        short mov1y = (short)(size + (Math.Sin((circle - 20) * (Math.PI / 180)) * radius));
        short mov2x = (short)(size + (Math.Cos((circle) * (Math.PI / 180)) * radius));
        short mov2y = (short)(size + (Math.Sin((circle) * (Math.PI / 180)) * radius));

        // MOVE
        vdu.Enqueue((byte)25, (byte)4);
        vdu.Enqueue(size, size);

        // MOVE
        vdu.Enqueue((byte)25, (byte)4);
        vdu.Enqueue(mov1x, mov1y);

        // PLOT triangle fill
        vdu.Enqueue((byte)25, (byte)85);
        vdu.Enqueue(mov2x, mov2y);

        switch (cntr)
        {
            case 1:
                            cd = 4;
                            break;
            case 4:
                            cd = -1;
                            break;
            case 7:
                            cd = 16;
                            break;
            case 10:
                            cd = -4;
                            break;
            case 13:
                            cd = 1;
                            break;
            case 16:
                            cd = -16;
                            break;
        }
        c += cd;
    }
}
</pre>
<p>which renders the following display on Windows Vista,</p>
<p><img src="http://www.smallshire.org.uk/sufficientlysmall/wp-content/wheel2.png" alt="Colour wheel display in Windows Vista" /></p>
<p>The Windows version is of higher quality because we have double the vertical resolution since Windows is used square pixels each half the size of the original rectangular pixels used in this screen mode on RISCOS. This is an example of a difference between historical implementations and our new implementation which we do not intend to address.</p>
<p>However, its possible to improve quality even further using the facilities of GDI+. We have implemented a new code (in the reserved for future expansion block) <code>VDU 23, 28, n</code> the purpose of which is to control rendering quality. In the current version we have implemented three quality levels. With the highest quality level, we get the following output:</p>
<p><img src="http://www.smallshire.org.uk/sufficientlysmall/wp-content/wheel3.png" alt="Antialiased colour wheel display in Windows Vista" /></p>
<p>which was simply never possible with the original Acorn BBC BASIC.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://www.smallshire.org.uk/sufficientlysmall">Sufficiently Small</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact legal@smallshire.org.uk so we can take legal action immediately.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span>]]></content:encoded>
			<wfw:commentRss>http://www.smallshire.org.uk/sufficientlysmall/2009/02/11/owl-basic-runtime-library-takes-shape/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>OWL BASIC Control Flow Graph</title>
		<link>http://www.smallshire.org.uk/sufficientlysmall/2008/11/23/owl-basic-control-flow-graph/</link>
		<comments>http://www.smallshire.org.uk/sufficientlysmall/2008/11/23/owl-basic-control-flow-graph/#comments</comments>
		<pubDate>Sun, 23 Nov 2008 19:55:52 +0000</pubDate>
		<dc:creator>Robert Smallshire</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[8 bit]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[OWL BASIC]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.smallshire.org.uk/sufficientlysmall/2008/11/23/owl-basic-control-flow-graph/</guid>
		<description><![CDATA[Since BBC BASIC does not use C-like nested scopes marked by braces to delineate loops and other blocks, the structure of such blocks is not captured in the Abstract Syntax Tree (AST); that is to say that the statements within a loop will not be child nodes of the opening loop statement such as FOR [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2008%2F11%2F23%2Fowl-basic-control-flow-graph%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2008%2F11%2F23%2Fowl-basic-control-flow-graph%2F&amp;source=robsmallshire&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Since BBC BASIC does not use C-like nested scopes marked by braces to delineate loops and other blocks, the structure of such blocks is not captured in the Abstract Syntax Tree (AST); that is to say that the statements within a loop will not be child nodes of the opening loop statement such as FOR or WHILE.  Furthermore, there is not necessarily a one-to-one correspondence between loop entry points such as FOR, and loop ends such as NEXT &#8211; a FOR loop may contain more than one  NEXT statement, and what is more, in convoluted cases involving GOTOs, a single NEXT statement may be re-used by several FOR loops. <a href="http://www.smallshire.org.uk/sufficientlysmall/2007/07/02/next-please-compiling-iteration-structures-in-bbc-basic/">Next please! Compiling Iteration Structures in BBC BASIC</a> for more information.</p>
<p>It is therefore required to pair each closing loop statement (<i>e.g.</i> NEXT or ENDWHILE) with its corresponding opening loop statement(s), and this is turn requires that the possible paths of execution through the program can be determined statically (<i>i.e.</i> at compile time) so that for each closing statement we can trace backwards through the program execution to the previous opening statement.  This also makes it possible to identify illegal constructs, such as ending a WHILE loop with a NEXT statement.</p>
<p>To achieve this, we must build a data structure called the Control Flow Graph (CFG). For each statement in the AST we determine all possible following statement. Ordinarily this is simply the next statement in the program, but we must also resolve line number references in GOTO, GOSUB, <i>etc.</i> and at each IF statement control flow may go in either of two directions. We do not resolve function or procedure calls when building the CFG, so each function or procedure becomes a separate connected-component in the resulting graph.</p>
<p>I&#8217;ve been working with the code to Acornsoft&#8217;s <i>Sphinx Adventure</i> from 1982 as a real-world BBC BASIC test program for the BBC Micro.</p>
<p><img src="http://www.smallshire.org.uk/images/BBC_Sphinx_Adventure.jpg" alt="Acornsoft Sphinx Adventure" /></p>
<p>I don&#8217;t know who the author is, but I&#8217;m willing to bet they never imagined their by now long-forgotten code would undergo the sort of analysis its about to receive!  Maybe the code in Sphinx Adventure is intentionally obfuscated, or maybe its just badly written, but some of the non-structured programming techniques such as jumping out of the middle of procedures never to return, are &#8216;interesting&#8217; to say the least.</p>
<p><img src="http://www.smallshire.org.uk/images/Sphinx_bbc_cfg.png" alt="Control Flow Graph for Acornsoft Sphinx Adventure" /></p>
<p>Each node in this image is a single statement in the program, and the arrows between the nodes indicate the program flow. Each connected group of nodes is a separate procedure, and the largest group of nodes to the top-left of the chart is the main program starting from the first line through a long trail of DATA statements.</p>
<p>The <a href="http://www.smallshire.org.uk/Sphinx.graphml">Sphinx.graphml</a> is browsable with <a href="http://www.yworks.com/en/products_yed_about.html">yEd</a>, which was also used to produce these diagrams.</p>
<p>Zooming in, we can see the CFG for a single procedure &#8211; in this case PROCF,</p>
<p>462 DEF PROCF(W): IFW=28 THEN PROCR(21): GOTO465<br />
463 IFO?W &lt;&gt; L  ANDO?W &lt;&gt; 1 THEN PROCR(7): PRINTA2$;&quot; here.&quot;: GOTO465 ELSE IFO?W2 &lt;&gt; 1 THEN PROCR(8): PRINTA2$;&quot;.&quot;: GOTO465<br />
464 IFW=27 ANDL=O?28 ANDWA=0 THEN PRINT&quot;Your bottle is now full of water.&quot;:WA=1 ELSE IFW=27 ANDL=O?28 THEN PRINT&quot;your bottle is already full.&quot; ELSE PROCR(21)<br />
465 ENDPROC</p>
<p><img src="http://www.smallshire.org.uk/images/Sphinx_bbc_procf_cfg.png" alt="Control Flow Graph for Acornsoft Sphinx Adventure PROCF" /></p>
<p>The label in each node indicates its logical line number in the original code and the type of statement the node represents at the abstract syntax level.</p>
<p>Now we have the basic CFGs we can analyse them to match up corresponding loop statements, and optionally perform optimizations such as moving invariant code out of loops and eliminating dead (unreachable) code fragments.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://www.smallshire.org.uk/sufficientlysmall">Sufficiently Small</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact legal@smallshire.org.uk so we can take legal action immediately.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span>]]></content:encoded>
			<wfw:commentRss>http://www.smallshire.org.uk/sufficientlysmall/2008/11/23/owl-basic-control-flow-graph/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OWL BASIC parser and abstract syntax tree</title>
		<link>http://www.smallshire.org.uk/sufficientlysmall/2008/11/23/owl-basic-parser-and-abstract-syntax-tree/</link>
		<comments>http://www.smallshire.org.uk/sufficientlysmall/2008/11/23/owl-basic-parser-and-abstract-syntax-tree/#comments</comments>
		<pubDate>Sun, 23 Nov 2008 09:59:38 +0000</pubDate>
		<dc:creator>Robert Smallshire</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[OWL BASIC]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.smallshire.org.uk/sufficientlysmall/2008/11/23/owl-basic-parser-and-abstract-syntax-tree/</guid>
		<description><![CDATA[Other personal projects, of both a software and familial nature have taken priority lately over my project to implement a BBC BASIC-a-like compiler for the .NET CLR, now called OWL BASIC in honour of the owl logo of the BBC&#8217;s Computer Literacy Project. Now I have some spare capacity to devote to the project, and [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2008%2F11%2F23%2Fowl-basic-parser-and-abstract-syntax-tree%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2008%2F11%2F23%2Fowl-basic-parser-and-abstract-syntax-tree%2F&amp;source=robsmallshire&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Other personal projects, of both a software and familial nature have taken priority lately over my project to implement a BBC BASIC-a-like compiler for the .NET CLR, now called OWL BASIC in honour of the owl logo of the BBC&#8217;s Computer Literacy Project. Now I have some spare capacity to devote to the project, and my brother Ian, who is part-way through his Computing Science degree and is another long-time BBC/RISC OS/Acorn computing enthusiast has joined the project &#8211; he&#8217;s starting work on the optional front-end detokenizer. We have opted to handle tokenized source files by detokenizing into text, and then retokenizing with our lexer &#8211; the reason being that the tokenized BBC BASIC files do not contain all of the tokens we need for our grammar, and detokenizing even very large programs is mimimum overhead compared to the parsing and complilation.</p>
<p>In this post, I want to take a look at the structure of the PLY parser and the classes defining storage for the Abstract Syntax Tree that is the product of streaming the lexer tokens through the parser.</p>
<h1>IronPython with PLY</h1>
<p>PLY requires that the grammar rules are placed in Python docstrings within methods that follow a specific naming convention; these docstrings are then parsed during parser initialisation to build the required parsing tables.  These tables are then cached in files for quicker start-up on subsequent runs.  PLY stores is cached tables as large files of generated Python code containing some very long expressions.  Unfortunately, these large expressions resulted in pathological behaviour of the IronPython parser, and stack overflow problems (although they were fine with regular CPython), and so some modifications to the PLY source was required to use Python pickling, rather than code generation, for storage and retrieval of the cached parsing tables. Performance is now <em>much</em> better, with a compiler startup time of many minutes reduced to a few seconds.</p>
<h1>BBC BASIC grammar structure</h1>
<p>I&#8217;ll start by pointing out that our current grammar definition is not perfect; even after the suitably caffeinated debugging session recommended in the PLY manual we still have 14 shift/reduce conflicts and 12 reduce/reduce conflicts. The former group are not serious, but the latter need to be addressed. There is no guarantee that it&#8217;s possible to parse BBC BASIC with a look-ahead left-to-right (LALR) grammar, owing the lack of a formal grammar definition for the language. The issues are resolvable, but may require stepping outside of the facilities provided by PLY &#8211; as we have done already for <code>DATA</code> statements.</p>
<p>The main structural part of our grammar is as follows:</p>
<pre class="brush: plain; title: ; notranslate">
program : statement_list;

statement_list : compound_statement
               | statement_list compound_statement;

compound_statement : lone_stmt_body stmt_terminator
                   | multi_statement stmt_terminator;

multi_statement : statement statements_tail;

statements_tail : statement_separator statement statements_tail
                | empty;

statement_separator : COLON;

stmt_terminator : EOL;

statement : stmt_body
          | empty;

lone_stmt_body : case_stmt;

stmt_body : beats_stmt
          | bput_stmt
          | call_stmt
          | circle_stmt
         ...
          | while_stmt
          | width_stmt
          | wait_stmt;
</pre>
<p>We have two recursively defined rules here: <code>statement_list</code> is defined in terms of itself, as is <code>statements_tail</code>. The former is used for collecting lists of statements or compound statements separated by line-breaks. The latter is used for accumulating statements forming compound statements separated by colons. The correct grammar for this was awkward to determine because many published grammars are for C-style languages which use statement terminators (<i>e.g.</i> semicolon) whereas BASIC uses Pascal-style statement <em>separators</em>, which can run in continguous sequences with empty statements. Some inspiration from a Pascal grammar and experimentation with <a href="http://ultragram.ust-solutions.qarchive.org/">UltraGram</a> led to workable solution. A minority of statements in BBC BASIC, such as <code>CASE</code> must occupy their own line, which must be handled in the grammar as <code>lone_stmt_body</code> &#8211; the less fussy majority of statements make up <code>stmt_body</code>:</p>
<h1>Abstract Syntax Tree construction</h1>
<p>As the parser matches each rule, an Abstract Syntax Tree (AST) node is generated. I&#8217;ll use the <code>BPUT</code> rule as a simple example which shows many features:</p>
<pre class="brush: python; title: ; notranslate">
def p_bput_stmt(p):
    '''bput_stmt : BPUT channel COMMA expr
                 | BPUT channel COMMA expr SEMICOLON'''
    if len(p) == 5:
        p[0] = Bput(channel = p[2], data = p[4], newline=True)
    elif len(p) == 6:
        p[0] = Bput(channel = p[2], data = p[4], newline=False)
    p[0].lineNum = p.lineno(1)
</pre>
<h2>Grammar rule encoding</h2>
<p>PLY encodes grammar rules in the doc-string of module level functions which accepts <i>p</i>, a list of the productions of other rules referenced such as <code>channel</code>, or terminals (<i>i.e.</i> tokens) such as <code>COMMA</code>. Our <code>BPUT</code> token represents the string &#8220;BPUT&#8221; in the source, <em>without</em> the following hash. The way the manual is written seems to suggest that the hash is part of the <code>BPUT</code> keyword, but simple experimentation with the BASIC interpreter, by inserting a space as in <code>BPUT #f%, 65</code> shows that the hash is a prefix to the integer representing a channel number.</p>
<p>The <code>BPUT</code> command has two syntaxes: The first form accepts a channel number (an single value prefixed by a hash) and an expression. The second form accepts an expression followed by a semicolon. There is no mention here of the type of the expressions &#8211; type-checking is a phase distinct from parsing which comes later.  These two forms of BPUT are not one-for-one equivalent with the two forms given in the BBC BASIC guide,</p>
<pre class="brush: plain; title: ; notranslate">
Syntax
        (1) BPUT#factor,numeric-expression
        (2) BPUT#factor,string-expression[;]
</pre>
<p>since our first rule matches syntaxes 1 and 2 (without the semicolon) and our second rule matches only syntax 2 (with the semicolon), illustrating how the syntax information in the manual must be converted into a YACC grammar suitable for PLY.</p>
<h2>Creating the AST node</h2>
<p>Crucially, our two syntax rules are of different length allowing us to use the length to determine which rule was matched. By PLY convention, the rule must place its resulting AST node in <code>p[0]</code>. For either match we create a <code>Bput</code> AST node which is a Python object representing <code>BPUT</code> and configure it with keyword parameters for the channel number, the data to be output, and a flag indicating whether a newline should be output following the data (<i>n.b.</i> this also depends on the type of <code>data</code> &#8211; we only output a newline for string data &#8211; by we account for that later in the type-checker once we have determined the type.) Each of these items will itself be an the root of an AST substree of nodes representing anything from a fairly mundane literal integer, to a complex expression. As a final step in configuring our new AST node, we attach line number information which is only available from terminal tokens &#8211; in this case we use the line-number from the <code>BPUT</code> token itself.</p>
<h1>Declaring the AST node classes</h1>
<p>Our requirements for our AST node classes are as follows:</p>
<ul>
<li>uniform interface to facilitate AST traversal for the later compiler stages</li>
<li>convenient syntax for declaring the structure of the many different types of AST nodes the langauge requires</li>
<li>conventient syntax for initializing new AST nodes as they are constructed by the grammar rules</li>
<li>attach formal type information and other information such as line numbers to the nodes</li>
</ul>
<p>Each AST node class started being writting out long hand, but it was clear that this was going to be a lot of boilerplate code for each class in functions which could not easily be factored out into base classes, such as <code>__init__</code> methods.  What was needed was a code generator for producing the classes based upon a simple specification, and this is where Python <em>metaclasses</em> come into their own.</p>
<p>Our specification for <code>BPUT</code> is something like this,</p>
<ol>
<li>A sub-node expression evaluating to a channel integer</li>
<li>A sub-node expression evaluating to a string or a number (<i>i.e.</i> a non-array type &#8211; a scalar</li>
<li>A flag indicating whether a newline should be appended after the data</li>
</ol>
<p>which we encode in Python using a declarative style as:</p>
<pre class="brush: python; title: ; notranslate">
class AstNode(object):
    &quot;AstNode - base class for all AST nodes&quot;
    __metaclass__ = AstMeta

    formal_type = TypeOption()
    actual_type = TypeOption()
    line_num = IntegerOption()

    # ... Code omitted here ...

class AstStatement(AstNode):
    &quot;AstStatement - base class for all statements&quot;
    formal_type = TypeOption(VoidType) # All statements have a type of 'void'
    actual_type = formal_type

class Bput(AstStatement):
    &quot;BPUT&quot;
    channel = Node(formalType=ChannelType)
    data    = Node(formalType=IntegerType)
    newline = BoolOption(False)
</pre>
<p>The work in transforming this declarative style into the boilerplate code we need is done by the <code>AstMeta</code> metaclass which introspects each class as it is constructed and converts our declarative style class attributes above, such as <code>Bput.channel</code> into the getters, setters, properties and intializers and storage we need, in the resulting class.  Our declared <code>Node</code>s can accept AST subtrees, whereas our <code>Option</code> types store simple integer, string, or bool properties attached to the node.</p>
<p>Thus, the contents of the <code>Bput</code> that is generated are quite different to what is shown above. When the Bput class is instantiated, its metaclass actually produces something which behaves like this:</p>
<pre class="brush: python; title: ; notranslate">
class AstNode(object):
    &quot;AstNode - base class for all AST nodes&quot;

    def __init__(self, lineNum = None):
        self.lineNum = lineNum

    # Line Number
    def _getLineNum(self):
        return self._getOption(&quot;line_num&quot;)

    def _setLineNum(self, line_num):
        self._setOption(&quot;line_num&quot;, line_num)

    formalType = property(getLineNum, setLineNum)

class AstStatement(AstNode):
    &quot;AstStatement - base class for all statements&quot;

    def __init__(self, formalType = None, actualType = None, **kwargs):
        self.formalType = None
        self.actualType = None
        super(AstStatement, self).__init__(kwargs)

    # Formal Type
    def _getFormalType(self):
        return self._getOption(&quot;formal_type&quot;)

    def _setFormalType(self, formal_type):
        self._setOption(&quot;formal_type&quot;, formal_type)

    formalType = property(getFormalType, setFormalType)

    # Actual Type
    def _getActualType(self):
        return self._getOption(&quot;actual_type&quot;)

    def _setActualType(self, actual_type):
        self._setActualType(&quot;actual_type&quot;, actual_type)

    actualType = property(getActualType, setActualType)

class Bput(AstStatement):
    &quot;BPUT&quot;

    # Channel
    def _getChannel(self):
        return self._getProperty(&quot;channel&quot;)

    def _setChannel(self, channel):
        self._setProperty(&quot;channel&quot;, channel)

    channel = property(getChannel, setChannel)

    # Data
    def _getData(self):
        return self._getProperty(&quot;data&quot;)

    def _setChannel(self, data):
        self._setProperty(&quot;data&quot;, data)

    data = property(getData, setData)

    # Newline
    def _getNewline(self):
        return self._getOption(&quot;newline&quot;)

    def _setNewline(self, data):
        self._setOption(&quot;newline&quot;, newline)

    newline = property(getNewline, setNewline)
</pre>
<p>This provides a uniform programming interface for the Bput object allowing simple manipulation of the Bput object itself, but also a standard interface to its child nodes allowing simple traversal by the various visitors which transform and analyse the AST in the later stages of the compiler.</p>
<h1>Visiting the AST</h1>
<p>Once the AST has been created by the parser, it can be analysed or manipulated by a visitor. One such visitor, which is an aid to debugging, transcribes each AST node into an XML representation. This is useful since it allows the AST to be conveniently examined using standard XML capable tools (<i>e.g.</i> a web browser) to aid debugging.</p>
<p>The following code, taken from line 374 of Acornsoft&#8217;s <i>Sphinx Adventure</i>,</p>
<p>378 IF ABS(L-26.5)&lt;1 ANDO?34=26 THEN PROCR(27): GOTO378</p>
<p>results in the following AST when rendered as XML following various other visitor passes to perform some simplification and type-checking,</p>
<pre class="brush: xml; title: ; notranslate">
&lt;If line_num=&quot;374&quot; actual_type=&quot;Void&quot; formal_type=&quot;Void&quot;&gt;
  &lt;false_clause&gt;
    &lt;None /&gt;
  &lt;/false_clause&gt;
  &lt;true_clause&gt;
    &lt;CallProcedure line_num=&quot;374&quot; actual_type=&quot;Void&quot; formal_type=&quot;Void&quot; name=&quot;R&quot;&gt;
      &lt;actual_parameters&gt;
        &lt;LiteralInteger line_num=&quot;374&quot; value=&quot;27&quot; actual_type=&quot;Integer&quot; /&gt;
      &lt;/actual_parameters&gt;
    &lt;/CallProcedure&gt;
    &lt;Goto line_num=&quot;374&quot; actual_type=&quot;Void&quot; formal_type=&quot;Void&quot;&gt;
      &lt;target_logical_line formal_type=&quot;Integer&quot;&gt;
        &lt;LiteralInteger line_num=&quot;374&quot; value=&quot;378&quot; actual_type=&quot;Integer&quot; /&gt;
      &lt;/target_logical_line&gt;
    &lt;/Goto&gt;
  &lt;/true_clause&gt;
  &lt;condition formal_type=&quot;Integer&quot;&gt;
    &lt;And line_num=&quot;374&quot; actual_type=&quot;Integer&quot; formal_type=&quot;Integer&quot;&gt;
      &lt;lhs formal_type=&quot;Integer&quot;&gt;
        &lt;LessThan line_num=&quot;374&quot; actual_type=&quot;Integer&quot; formal_type=&quot;Integer&quot;&gt;
          &lt;lhs&gt;
            &lt;AbsFunc line_num=&quot;374&quot;&gt;
              &lt;factor formal_type=&quot;Numeric&quot;&gt;
                &lt;Minus line_num=&quot;374&quot; actual_type=&quot;Float&quot;&gt;
                  &lt;lhs formal_type=&quot;Numeric&quot;&gt;
                    &lt;Variable line_num=&quot;374&quot; actual_type=&quot;Float&quot; identifier=&quot;L&quot; /&gt;
                  &lt;/lhs&gt;
                  &lt;rhs formal_type=&quot;Numeric&quot;&gt;
                    &lt;LiteralFloat line_num=&quot;374&quot; value=&quot;26.5&quot; actual_type=&quot;Float&quot; /&gt;
                  &lt;/rhs&gt;
                &lt;/Minus&gt;
              &lt;/factor&gt;
            &lt;/AbsFunc&gt;
          &lt;/lhs&gt;
          &lt;rhs&gt;
            &lt;LiteralInteger line_num=&quot;374&quot; value=&quot;1&quot; actual_type=&quot;Integer&quot; /&gt;
          &lt;/rhs&gt;
        &lt;/LessThan&gt;
      &lt;/lhs&gt;
      &lt;rhs formal_type=&quot;Integer&quot;&gt;
        &lt;Equal line_num=&quot;374&quot; actual_type=&quot;Integer&quot; formal_type=&quot;Integer&quot;&gt;
          &lt;lhs&gt;
            &lt;DyadicByteIndirection line_num=&quot;374&quot; actual_type=&quot;Byte&quot; formal_type=&quot;Byte&quot;&gt;
              &lt;base formal_type=&quot;Address&quot;&gt;
                &lt;Cast line_num=&quot;374&quot; actual_type=&quot;Address&quot; source_type=&quot;Float&quot; target_type=&quot;Address&quot; formal_type=&quot;Address&quot;&gt;
                  &lt;value&gt;
                    &lt;Variable line_num=&quot;374&quot; actual_type=&quot;Float&quot; identifier=&quot;O&quot; /&gt;
                  &lt;/value&gt;
                &lt;/Cast&gt;
              &lt;/base&gt;
              &lt;offset formal_type=&quot;Integer&quot;&gt;
                &lt;LiteralInteger line_num=&quot;374&quot; value=&quot;34&quot; actual_type=&quot;Integer&quot; /&gt;
              &lt;/offset&gt;
            &lt;/DyadicByteIndirection&gt;
          &lt;/lhs&gt;
          &lt;rhs&gt;
            &lt;LiteralInteger line_num=&quot;374&quot; value=&quot;26&quot; actual_type=&quot;Integer&quot; /&gt;
          &lt;/rhs&gt;
        &lt;/Equal&gt;
      &lt;/rhs&gt;
    &lt;/And&gt;
  &lt;/condition&gt;
&lt;/If&gt;
</pre>
<hr/>Copyright &copy; 2012 <strong><a href="http://www.smallshire.org.uk/sufficientlysmall">Sufficiently Small</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact legal@smallshire.org.uk so we can take legal action immediately.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span>]]></content:encoded>
			<wfw:commentRss>http://www.smallshire.org.uk/sufficientlysmall/2008/11/23/owl-basic-parser-and-abstract-syntax-tree/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NEXT please! Compiling iteration structures in BBC BASIC</title>
		<link>http://www.smallshire.org.uk/sufficientlysmall/2007/07/02/next-please-compiling-iteration-structures-in-bbc-basic/</link>
		<comments>http://www.smallshire.org.uk/sufficientlysmall/2007/07/02/next-please-compiling-iteration-structures-in-bbc-basic/#comments</comments>
		<pubDate>Mon, 02 Jul 2007 16:32:37 +0000</pubDate>
		<dc:creator>Robert Smallshire</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[OWL BASIC]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.smallshire.org.uk/sufficientlysmall/2007/07/02/next-please-compiling-iteration-structures-in-bbc-basic/</guid>
		<description><![CDATA[This posting has been re-written from an earlier version which contained unnecessary complexity Following on from my proposal on how to compiler BBC BASIC functions with variant return types, in response to Richard Russell’s compilation challenges, I’d like to move on to compiling BBC BASIC loop structures. Nonetheless, several readers have comments how useful even [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2007%2F07%2F02%2Fnext-please-compiling-iteration-structures-in-bbc-basic%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.smallshire.org.uk%2Fsufficientlysmall%2F2007%2F07%2F02%2Fnext-please-compiling-iteration-structures-in-bbc-basic%2F&amp;source=robsmallshire&amp;style=normal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><em>This posting has been re-written from an earlier version which contained unnecessary complexity</em></p>
<p>Following on from my proposal on how to compiler BBC BASIC functions with variant return types, in response to Richard Russell’s <a href="http://www.smallshire.org.uk/sufficientlysmall/2007/06/10/writing-a-bbc-basic-compiler-for-the-clr/#comment-1579">compilation challenges</a>, I’d like to move on to compiling BBC BASIC loop structures. Nonetheless, several readers have comments how useful even a compiler that did not support these features would be.</p>
<p>The claimed difficulty arises is because BBC BASIC maintains a stack at run-time for managing loop structures such as <code>FOR..NEXT</code>, <code>REPEAT..UNTIL</code> and <code>WHILE..ENDWHILE</code>. As the interpreter executes the program it presumably uses the instructions it encounters to manipulate this stack. They key point here is that the tokens listed above are not merely loop delimiters used by the parser, they are actually statements which modify the internal state of the interpreter.</p>
<p>The situation is further complicated by the quirky behaviour of the <code>NEXT</code> statement. First of all, the loop variable following the <code>NEXT</code> is optional. If it is omitted the next iteration of the <code>FOR</code> loop which is topmost on the stack (<em>i.e.</em> the inner-most loop) is executed. However, it is also possible to supply a comma-separated list of loop variables, for example <code>NEXT i%,j%</code>. This is equivalent to <code>NEXT i% : NEXT j%</code>.</p>
<p>Richard goes on to illustrate the point with a real-world example,</p>
<blockquote><p>Here there are two NEXT I% statements; which gets used depends at run-time on the contents of the array. This is a real-world example (although the code could no doubt be written more elegantly).</p></blockquote>
<p>DEF FNscan(A()) : LOCAL I%<br />
    FOR I% = 0 TO DIM(A(),1)<br />
        IF A(I%) = 0 THEN<br />
            I% = DIM(A(),1)<br />
            NEXT I%<br />
            = TRUE<br />
        ENDIF<br />
        REM Some more code here<br />
    NEXT I%<br />
= FALSE</p>
<p>This time, I will use a different example, which is very similar in structure to Richard’s code, but which excludes the array, for the sake of clarity.</p>
<p>FOR i% = 1 TO 5<br />
    IF i% = 3 THEN<br />
        PRINT &quot;Three!&quot;<br />
        NEXT<br />
    ENDIF<br />
    PRINT &quot;i% is &quot;;i%<br />
NEXT</p>
<p>Note there is one <code>FOR</code> statement and two <code>NEXT</code> statements, so it is not possible to pair them. I simply print the loop counter, or in one case print a different string and <code>NEXT</code> early.</p>
<p>Formatted like this we can see that the inner <code>NEXT</code> is exactly like the <code>continue</code> statement in C#.</p>
<pre class="brush: csharp; title: ; notranslate">
for (int i = 1; i &lt;= 5 ; ++i)
{
   if (i == 3)
   {
      Console.WriteLine(&quot;Three!&quot;);
      continue; // next
   }
   Console.WriteLine(&quot;i% is {0}&quot;, counter);
   continue; //next
}
</pre>
<p>So, we can do something isomorphic in C#, C# is compilable to CIL, ergo this particular BBC BASIC construct is compilable to C#. Obviously.</p>
<p>However, more nefarious constructs are possible in BBC BASIC, such as this:</p>
<p>FOR i% = 1 TO 5<br />
FOR j% = 1 TO 5<br />
PRINT &quot;i% = &quot;;i%,&quot;j% = &quot;;j%<br />
NEXT i%</p>
<p>where we iterate on the outer loop, from &#8216;within&#8217; the inner one.  It may be possible to weed these out at compile time in simple cases such as this, and replace the <code>FOR j%= 1</code> with a simple assignment.  If not, its definitely possible to deal with it at run-time</p>
<p>The equivalent code using the C# a simple ForNext class I devised looks like this:</p>
<pre class="brush: csharp; title: ; notranslate">
ForNext outer = new ForNext(&quot;i%&quot;, 1, 5, 1);
outer.execute(delegate(int counter)
        {
            ForNext inner = new ForNext(&quot;j%&quot;, 1, 5, 1);
            inner.execute(delegate(int counter2)
            {
                Console.WriteLine(&quot;i% = {0} j% = {1}&quot;, counter, counter2);
                ForNext.Next(&quot;i%&quot;);
            });
         });
</pre>
<p>For the run-time solution, I create a <code>ForNext</code> loop object, initialized with the counter name which is just a label and the start, end and step values. I then pass the loop body to the <code>ForNext</code> object as a C# anonymous delegate. <code>NEXT</code> statements are implemented as calls to the static method <code>ForNext.Next()</code> with an optional counter name.</p>
<p>When run, the code produces,</p>
<pre class="brush: plain; title: ; notranslate">
i% = 1     j% = 1
i% = 2     j% = 1
i% = 3     j% = 1
i% = 4     j% = 1
i% = 5     j% = 1
</pre>
<p>Of course, some machinery in the <code>ForNext</code> class is required to make this work. In this case we use the .NET exception handling machinery to manage the stack of <code>FOR..NEXT</code> loops on our behalf, calling <code>ForNext.Next()</code> exits the current iteration of the top-most loop on the stack and if necessary begins the next iteration.</p>
<pre class="brush: csharp; title: ; notranslate">
class ForNext
{
    public delegate void Body(int counter);
    private string id;
    private int end;
    private int step;
    private int counter;

    private class NextException : System.Exception
    {
        public string id;

        public NextException(string id)
        {
            this.id = id;
        }

        public NextException() :
            this(null)
        {
        }
    }

    public ForNext(string id, int start, int end, int step)
    {
        this.id = id;
        this.counter = start;
        this.end   = end;
        this.step  = step;
    }

    public void execute(Body body)
    {
        while (counter &lt;= end)
        {
            try
            {
                body(counter);
            }
            catch (NextException e)
            {
                if (e.id != null &amp;&amp; e.id != this.id)
                {
                    throw;
                }
                counter += step;
            }
        }
    }

    public static void Next()
    {
        if (counter &lt; end)
        {
            throw new NextException();
        }
    }

    public static void Next(string id)
    {
        if (counter &lt; end)
        {
            throw new NextException(id);
        }
    }
}
</pre>
<p>Note how in this example we pass the loop counter label as <code>ForNext.Next("i%")</code>.</p>
<p>Of course, relying on the .NET exception handling mechanism for all such loops in BBC BASIC would be overkill. The majority of <code>FOR..NEXT</code> constructs are must simpler than this. The challenge moves on to detecting the simple cases using static analysis of the program to be compiled, and generating normal loop code in these simple cases. We would only fall back to the mechanism described here when required, if multiple unlabelled <code>NEXT</code> statements are present. It remains to be seen how feasible detection of these cases will be.</p>
<p>Of course, in functional languages, explicit iteration structures such as <code>FOR..NEXT</code> need not be present at all, since all iteration is achieved through recursion, usually with tail-calls. Another feature invented in the functional language LISP and now commonly available in more sophisticated languages is the concept of <a href="http://en.wikipedia.org/wiki/Continuation">continuations</a>, which are basically &#8220;GOTOs with parameters&#8221;.  Both exception handling, as used in this post, and other complex control structures can be implemented using continuations, as can all the iteration structures of BBC BASIC, even with mismatched <code>FOR..NEXT</code> statements, even when the <code>NEXT</code> statement is not labelled with a counter variable.</p>
<hr/>Copyright &copy; 2012 <strong><a href="http://www.smallshire.org.uk/sufficientlysmall">Sufficiently Small</a></strong>. This Feed is for personal non-commercial use only. If you are not reading this material in your news aggregator, the site you are looking at is guilty of copyright infringement. Please contact legal@smallshire.org.uk so we can take legal action immediately.<br/><span style="float: right;font-size: 7pt"><a href="http://blog.taragana.com/index.php/archive/wordpress-plugins-provided-by-taraganacom/">Plugin</a> by <a href="http://www.taragana.com/">Taragana</a></span>]]></content:encoded>
			<wfw:commentRss>http://www.smallshire.org.uk/sufficientlysmall/2007/07/02/next-please-compiling-iteration-structures-in-bbc-basic/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

