for ActionScript3
BulletMLAS Test - Source code
package {
  import flash.display.Sprite;
  import flash.display.TextField;
  import flash.display.TextFieldAutoSize;
  import flash.display.Bitmap;
  import flash.display.BitmapData;
  import flash.events.Event;
  import flash.events.EventType;
  import flash.text.TextFormat;
  import flash.geom.Matrix;
  import flash.geom.Rectangle;
  import flash.util.getTimer;
  import abagames.util.bulletml.BulletML;
  import abagames.util.bulletml.BulletsManager;
  import abagames.util.bulletml.Bullet;

  // Use '-default-size 360 480 -default-frame-rate 60 -optimize=true'
  //  as the additional compiler arguments.
  public class Test extends Sprite {
    var bmlXml:XML = 
<bulletml>
 <action label="top">
 <repeat> <times>8</times>
 <action>
  <fire>
   <direction>$rand*360</direction>
   <bulletRef label="eye"/>
  </fire>
  <wait>30</wait>
 </action>
 </repeat>
 <vanish/>
 </action>

 <bullet label="eye">
 <speed>0</speed>
 <action>
 <changeSpeed>
  <speed>10</speed>
  <term>400</term>
 </changeSpeed>
 <changeDirection>
  <direction type="sequence">$rand * 5 - 2.5</direction>
  <term>9999</term>
 </changeDirection>
 <repeat> <times>99</times>
 <action>
  <fire>
   <direction type="relative">0</direction>
   <bulletRef label="shadow"/>
  </fire>
  <wait>16 - $rank * 13</wait>
 </action>
 </repeat>
 </action>
 </bullet>

 <bullet label="shadow">
 <speed>0</speed>
 <action>
 <wait>20</wait>
 <fire>
  <direction type="relative">90</direction>
  <bullet/>
 </fire>
 <fire>
  <direction type="relative">-90</direction>
  <bullet/>
 </fire>
 <vanish/>
 </action>
 </bullet>
</bulletml>

    public function Test() {
      addEventListener(EventType.ENTER_FRAME, onEnterFrame);
    }
    
    private var isFirst:Boolean = true;
    private var bulletsManager:BulletsManagerImpl;
    private var prevTick:uint = 0;
    private var fps:Number = 60;
    private var buffer:BitmapData;
    private var screen:Bitmap;

    public function onEnterFrame(evt:Event) {
      if (isFirst) {
        isFirst = false;
        init();
      }
      buffer.fillRect(buffer.rectangle, 0xaabbdd);
      bulletsManager.run(buffer);
      bulletNum.text = String(bulletsManager.bulletCount());
      var t:uint = getTimer();
      var cfps:Number = 1000 / (t - prevTick);
      fps += (cfps - fps) * 0.2;
      var fi:int = int(fps);
      var ff:int = int((fps - fi) * 10);
      fpsNum.text = String(fi) + "." + String(ff);
      prevTick = t;
    }
    
    private function init() {
      BulletImpl.rank = 1;
      BulletImpl.screenWidth = 360;
      BulletImpl.screenHeight = 480;
      BulletImpl.scale = 1;
      bulletsManager = new BulletsManagerImpl;
      addBullet(bmlXml, bulletsManager, BulletImpl.screenWidth / 2, BulletImpl.screenHeight / 4);
      addBullet(bmlXml, bulletsManager, BulletImpl.screenWidth / 3, BulletImpl.screenHeight / 3);
      addBullet(bmlXml, bulletsManager, BulletImpl.screenWidth / 3 * 2, BulletImpl.screenHeight / 3);
      buffer = new BitmapData(BulletImpl.screenWidth, BulletImpl.screenHeight, false, 0);
      screen = new Bitmap(buffer);
      addChild(screen);
      initText();
    }
    
    private function addBullet(bmlXml:XML, bm:BulletsManager, x:Number, y:Number) {
      var bml:BulletML = new BulletML;
      bml.init(bmlXml);
      bm.addBullet(bml, x, y, 0, 0);
    }

    private var bulletNum:TextField;
    private var fpsNum:TextField;
    
    public function initText() {
      bulletNum = new TextField;
      bulletNum.x = BulletImpl.screenWidth - 80 - 20 * BulletImpl.scale;
      bulletNum.y = 10 * BulletImpl.scale;
      bulletNum.autoSize = TextFieldAutoSize.RIGHT;
      fpsNum = new TextField;
      fpsNum.x = BulletImpl.screenWidth - 80 - 20 * BulletImpl.scale;
      fpsNum.y = 30 * BulletImpl.scale;
      fpsNum.autoSize = TextFieldAutoSize.RIGHT;
      var format:TextFormat = new TextFormat;
      format.font = "Verdana";
      format.color = 0x000000;
      format.size = 20 * BulletImpl.scale;
      bulletNum.defaultTextFormat = format;
      fpsNum.defaultTextFormat = format;
      addChild(bulletNum);
      addChild(fpsNum);
    }
  }
  
  private class BulletsManagerImpl implements BulletsManager {
    private var bullets:Array = new Array;

    public function addBullet(bml:BulletML, x:Number, y:Number,
                              deg:Number, speed:Number):Bullet {
      var b:BulletImpl = new BulletImpl(bml, this, x, y, deg, speed);
      bullets.push(b);
      return b;
    }
    
    public function run(buf:BitmapData) {
      for each (var b:BulletImpl in bullets)
        b.run(buf);
      for (var i:int = 0; i < bullets.length; ) {
        var b:BulletImpl = BulletImpl(bullets[i]);
        if (b.isEnd()) {
          bullets.splice(i, 1);
        } else {
          i++;
        }
      }
    }
    
    public function bulletCount():int {
      return bullets.length;
    }
  }

  private class BulletImpl implements Bullet {
    public static var screenWidth:int = 360;
    public static var screenHeight:int = 480;
    public static var scale:Number = 1;
    public static var rank:Number = 0.5;
    private var bml:BulletML;
    private var bm:BulletsManager;
    private var x:Number;
    private var y:Number;
    private var rotation:Number;
    private var speed:Number;
    private var acx:Number;
    private var acy:Number;
    private var matrix:Matrix;
    private var shape:BitmapData;
    private var rect:Rectangle;
    private var isVanished:Boolean;
    
    public function BulletImpl(bml:BulletML, bm:BulletsManager,
                               x:Number, y:Number, deg:Number, speed:Number) {
      this.bml = bml;
      this.bm = bm;
      this.x = x;
      this.y = y;
      rotation = deg;
      this.speed = speed;
      acx = acy = 0;
      //matrix = new Matrix;
      //shape = new BitmapData(2, 8, false, 0xffffff);
      rect = new Rectangle(0, 0, 5, 5);
      isVanished = false;
    }
    
    public function run(buf:BitmapData) {
      bml.run(this, bm);
      x += Math.sin(rotation * Math.PI / 180) * speed * scale;
      y -= Math.cos(rotation * Math.PI / 180) * speed * scale;
      x += acx * scale;
      y += acy * scale;
      if (x < 0 || x >= screenWidth || y < 0 || y >= screenHeight) {
        vanish();
        return;
      }
      /*matrix.identity();
      matrix.rotate(rotation * Math.PI / 180);
      matrix.translate(x, y);
      buf.draw(shape, matrix);*/
      rect.x = x;
      rect.y = y;
      buf.fillRect(rect, 0xffffff);
    }
    
    public function isEnd():Boolean {
      return isVanished;
    }
    
    public function getDirection():Number {
      return rotation;
    }

    public function setDirection(v:Number) {
      rotation = v;
    }

    public function getAimDirection():Number {
      return 180;
    }

    public function getSpeed():Number {
      return speed;
    }

    public function setSpeed(v:Number) {
      speed = v;
    }

    public function getX():Number {
      return x;
    }

    public function getY():Number {
      return y;
    }

    public function getHorizontal():Number {
      return acx;
    }

    public function setHorizontal(v:Number) {
      acx = v;
    }

    public function getVertical():Number {
      return acy;
    }
    
    public function setVertical(v:Number) {
      acy = v;
    }

    public function vanish() {
      isVanished = true;
    }

    public function getRand():Number {
      return Math.random();
    }

    public function getRank():Number {
      return rank;
    }
  }
}