Dienstag, 11. August 2015

Previsit a datastructure

Recently I had to write a small and relatively simple compiler and came across a problem. For the function prologue the stack pointer should be decreased by 4 * number of local variables. Compilers work with a datastructure so called "Abstract Syntax Tree". The important part is that it was realized with the Visitor design pattern. I was looking for a simple solution to know the number of local variables in the moment I want to decrease the stack pointer. I couldn't think of non-complex code and came across this elegant and simple solution:

Here we have the normal Visitor:
public interface ASTVisitor {

    public void visit(FunctionDefinitionExpression e);
    public void visit(DeclarationStatement s);
    // ...

}
All subtypes implement the accept method for the Visitor:
public class PrimaryExpression extends Expression {

    // ...
 
    @Override
    public void accept(ASTVisitor v) {
        v.visit(this);
    }

}
Here we have the implemention and the main logic:
public class ASTVisitorImpl implements ASTVisitor {

    @Override
    public void visit(FunctionDefinitionExpression e) {

        int n = 0;

        // here we will use our custom PreVisitor
        // and override our desired method
        funcDefinition.accept(new PreVisitor() {
         
            @Override
            public void visit(DeclarationStatement decl) {

                // add here your logic e.g.
                n++;
    
            }
         });

    }
}
That's our simple PreVisitor:
public class PreVisitor implements ASTVisitor {

    @Override
    public void visit(DeclarationStatement declarationStatement) {
    }

    @Override
    public void visit(BinaryExpression binaryExpression) {
        binaryExpression.elem1.accept(this);
        binaryExpression.elem2.accept(this);
    }

    // ...

}

So the solution was simply to create another subtype of the the same ASTVisitor interface and implement there all methods and just the logic to traverse the whole datastructure (Abstract Syntax Tree). At the moment you want to have a specific information without continuing at this point, you call the PreVisitor and override the desired method - et voilà you have an elegant solution!

Montag, 10. August 2015

Apple Swift: Getting Started #1

Apple released a newer version of its new programming Language Swift. Here are a few starter links and hints, when working with the new version Swift 2:

This link is your headquarter:
https://developer.apple.com/swift/resources/
from there you get the recommendable book "The Swift Programming Language (Swift 2 Prerelease)" and many code examples. The book's writing style is casual and animates to read more.
Unfortunately the code examples are not updated (I hope they will be in future) and this was the main reason to create this blog post, to give absolute beginners help with the start up. In all code samples you can use the converter, which automatically converts the older syntax 1.2 to the newer syntax, but there are still some errors in the samples left.

Adventure: Building a SpriteKit Game Using Swift:
AdventureScene.swift before
// ...

override init(size: CGSize) {
    leafEmitterATemplate = SKEmitterNode(fileNamed: "Leaves_01")
    leafEmitterBTemplate = SKEmitterNode(fileNamed: "Leaves_02")
    projectileSparkEmitterTemplate = SKEmitterNode(fileNamed: "ProjectileSplat")
    spawnEmitterTemplate = SKEmitterNode(fileNamed: "Spawn")
        
    super.init(size: size)

    players[0] = defaultPlayer
}

// ...

func loadWorld() {
    // ...
    let templateWorld = scene.children.first!.copy() as! SKNode
    // ...
}

// ...

func configureConnectedGameControllers() {
    // ...
    assignPresetController(controller, toIndex: playerIndex)
    // ...
}

// ...

func gameControllerDidConnect(notification: NSNotification) {
    // ...
    assignPresetController(controller, toIndex: playerIndex)
    // ...
}

// ...

func assignUnknownController(controller: GCController) {
    // ...
    controller.playerIndex = index
    // ...
}

// ...

func configureController(controller: GCController, forPlayer player: Player) {
    // ...
    loadHUDForPlayer(player, atIndex: player.controller!.playerIndex)
    // ...
}

AdventureScene.swift after
// ...

override init(size: CGSize) {
    leafEmitterATemplate = SKEmitterNode(fileNamed: "Leaves_01")!
    leafEmitterBTemplate = SKEmitterNode(fileNamed: "Leaves_02")!
    projectileSparkEmitterTemplate = SKEmitterNode(fileNamed: "ProjectileSplat")!
    spawnEmitterTemplate = SKEmitterNode(fileNamed: "Spawn")!
        
    super.init(size: size)

    players[0] = defaultPlayer
}

// ...

func loadWorld() {
    // ...
        let templateWorld = scene!.children.first!.copy() as! SKNode
    // ...
}

// ...

func configureConnectedGameControllers() {
    // ...
    assignPresetController(controller, toIndex: playerIndex.rawValue)
    // ...
}

// ...

func gameControllerDidConnect(notification: NSNotification) {
    // ...
    assignPresetController(controller, toIndex: playerIndex.rawValue)
    // ...
}

// ...

func assignUnknownController(controller: GCController) {
    // ...
    controller.playerIndex = GCControllerPlayerIndex(rawValue: index)!
    // ...
}

// ...

func configureController(controller: GCController, forPlayer player: Player) {
    // ...
    loadHUDForPlayer(player, atIndex: player.controller!.playerIndex.rawValue)
    // ...
}

All other errors are of the same kind "value of optional type" and you can simply click the QuickFix.