How to resolve the algorithm Compiler/AST interpreter step by step in the Wren programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Compiler/AST interpreter step by step in the Wren programming language

Table of Contents

Problem Statement

An AST interpreter interprets an Abstract Syntax Tree (AST) produced by a Syntax Analyzer. Take the AST output from the Syntax analyzer task, and interpret it as appropriate. Refer to the Syntax analyzer task for details of the AST. Notes: Because of the simple nature of our tiny language, Semantic analysis is not needed. Your interpreter should use C like division semantics, for both division and modulus. For division of positive operands, only the non-fractional portion of the result should be returned. In other words, the result should be truncated towards 0. This means, for instance, that 3 / 2 should result in 1. For division when one of the operands is negative, the result should be truncated towards 0. This means, for instance, that 3 / -2 should result in -1. Your solution should pass all the test cases above and the additional tests found Here. The C and Python versions can be considered reference implementations.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Compiler/AST interpreter step by step in the Wren programming language

Source code in the wren programming language

import "./dynamic" for Enum, Struct, Tuple
import "./fmt" for Conv
import "./ioutil" for FileUtil

var nodes = [
    "Ident",
    "String",
    "Integer",
    "Sequence",
    "If",
    "Prtc",
    "Prts",
    "Prti",
    "While",
    "Assign",
    "Negate",
    "Not",
    "Mul",
    "Div",
    "Mod",
    "Add",
    "Sub",
    "Lss",
    "Leq",
    "Gtr",
    "Geq",
    "Eql",
    "Neq",
    "And",
    "Or"
]

var Node = Enum.create("Node", nodes)

var Tree = Struct.create("Tree", ["nodeType", "left", "right", "value"])

// dependency: Ordered by Node value, must remain in same order as Node enum
var Atr = Tuple.create("Atr", ["enumText", "nodeType"])

var atrs = [
    Atr.new("Identifier", Node.Ident),
    Atr.new("String", Node.String),
    Atr.new("Integer", Node.Integer),
    Atr.new("Sequence", Node.Sequence),
    Atr.new("If", Node.If),
    Atr.new("Prtc", Node.Prtc),
    Atr.new("Prts", Node.Prts),
    Atr.new("Prti", Node.Prti),
    Atr.new("While", Node.While),
    Atr.new("Assign", Node.Assign),
    Atr.new("Negate", Node.Negate),
    Atr.new("Not", Node.Not),
    Atr.new("Multiply", Node.Mul),
    Atr.new("Divide", Node.Div),
    Atr.new("Mod", Node.Mod),
    Atr.new("Add", Node.Add),
    Atr.new("Subtract", Node.Sub),
    Atr.new("Less", Node.Lss),
    Atr.new("LessEqual", Node.Leq),
    Atr.new("Greater", Node.Gtr),
    Atr.new("GreaterEqual", Node.Geq),
    Atr.new("Equal", Node.Eql),
    Atr.new("NotEqual", Node.Neq),
    Atr.new("And", Node.And),
    Atr.new("Or", Node.Or),
]

var stringPool = []
var globalNames = []
var globalValues = {}

var reportError = Fn.new { |msg| Fiber.abort("error : %(msg)") }

var makeNode = Fn.new { |nodeType, left, right| Tree.new(nodeType, left, right, 0) }

var makeLeaf = Fn.new { |nodeType, value| Tree.new(nodeType, null, null, value) }

// interpret the parse tree
var interp  // recursive function
interp = Fn.new { |x|
    if (!x) return 0
    var nt = x.nodeType
    if (nt == Node.Integer) return x.value
    if (nt == Node.Ident) return globalValues[x.value]
    if (nt == Node.String) return x.value
    if (nt == Node.Assign) {
        var n = interp.call(x.right)
        globalValues[x.left.value] = n
        return n
    }
    if (nt == Node.Add) return interp.call(x.left) +  interp.call(x.right)
    if (nt == Node.Sub) return interp.call(x.left) -  interp.call(x.right)
    if (nt == Node.Mul) return interp.call(x.left) *  interp.call(x.right)
    if (nt == Node.Div) return (interp.call(x.left) / interp.call(x.right)).truncate
    if (nt == Node.Mod) return interp.call(x.left) %  interp.call(x.right)
    if (nt == Node.Lss) return Conv.btoi(interp.call(x.left) <  interp.call(x.right))
    if (nt == Node.Gtr) return Conv.btoi(interp.call(x.left) >  interp.call(x.right))
    if (nt == Node.Leq) return Conv.btoi(interp.call(x.left) <= interp.call(x.right))
    if (nt == Node.Eql) return Conv.btoi(interp.call(x.left) == interp.call(x.right))
    if (nt == Node.Neq) return Conv.btoi(interp.call(x.left) != interp.call(x.right))
    if (nt == Node.And) return Conv.btoi(Conv.itob(interp.call(x.left)) && Conv.itob(interp.call(x.right)))
    if (nt == Node.Or)  return Conv.btoi(Conv.itob(interp.call(x.left)) || Conv.itob(interp.call(x.right)))
    if (nt == Node.Negate) return -interp.call(x.left)
    if (nt == Node.Not) return (interp.call(x.left) == 0) ? 1 : 0
    if (nt == Node.If) {
        if (interp.call(x.left) != 0) {
            interp.call(x.right.left)
        } else {
            interp.call(x.right.right)
        }
        return 0
    }
    if (nt == Node.While) {
        while (interp.call(x.left) != 0) interp.call(x.right)
        return 0
    }
    if (nt == Node.Prtc) {
        System.write(String.fromByte(interp.call(x.left)))
        return 0
    }
    if (nt == Node.Prti) {
        System.write(interp.call(x.left))
        return 0
    }
    if (nt == Node.Prts) {
        System.write(stringPool[interp.call(x.left)])
        return 0
    }
    if (nt == Node.Sequence) {
        interp.call(x.left)
        interp.call(x.right)
        return 0
    }
    reportError.call("interp: unknown tree type %(x.nodeType)")
}

var getEnumValue = Fn.new { |name|
    for (atr in atrs) {
        if (atr.enumText == name) return atr.nodeType
    }
    reportError.call("Unknown token %(name)")
}

var fetchStringOffset = Fn.new { |s|
    var d = ""
    s = s[1...-1]
    var i = 0
    while (i < s.count) {
        if (s[i] == "\\" && (i+1) < s.count) {
            if (s[i+1] == "n") {
                d = d + "\n"
                i = i + 1
            } else if (s[i+1] == "\\") {
                d = d + "\\"
                i = i + 1
            }
        } else {
            d = d + s[i]
        }
        i = i + 1
    }
    s = d
    for (i in 0...stringPool.count) {
        if (s == stringPool[i]) return i
    }
    stringPool.add(s)
    return stringPool.count - 1
}

var fetchVarOffset = Fn.new { |name|
    for (i in 0...globalNames.count) {
        if (globalNames[i] == name) return i
    }
    globalNames.add(name)
    return globalNames.count - 1
}

var lines = []
var lineCount = 0
var lineNum = 0

var loadAst  // recursive function
loadAst = Fn.new {
    var nodeType = 0
    var s = ""
    if (lineNum < lineCount) {
        var line = lines[lineNum].trimEnd(" \t")
        lineNum = lineNum + 1
        var tokens = line.split(" ").where { |s| s != "" }.toList
        var first = tokens[0]
        if (first[0] == ";") return null
        nodeType = getEnumValue.call(first)
        var le = tokens.count
        if (le == 2) {
            s = tokens[1]
        } else if (le > 2) {
            var idx = line.indexOf("\"")
            s = line[idx..-1]
        }
    }
    if (s != "") {
        var n
        if (nodeType == Node.Ident) {
            n = fetchVarOffset.call(s)
        } else if (nodeType == Node.Integer) {
            n = Num.fromString(s)
        } else if (nodeType == Node.String) {
            n = fetchStringOffset.call(s)
        } else {
            reportError.call("Unknown node type: %(s)")
        }
        return makeLeaf.call(nodeType, n)
    }
    var left  = loadAst.call()
    var right = loadAst.call()
    return makeNode.call(nodeType, left, right)
}

lines = FileUtil.readLines("ast.txt")
lineCount = lines.count
var x = loadAst.call()
interp.call(x)


  

You may also check:How to resolve the algorithm Caesar cipher step by step in the Lambdatalk programming language
You may also check:How to resolve the algorithm Terminal control/Ringing the terminal bell step by step in the 8086 Assembly programming language
You may also check:How to resolve the algorithm Secure temporary file step by step in the Tcl programming language
You may also check:How to resolve the algorithm Sub-unit squares step by step in the FreeBASIC programming language
You may also check:How to resolve the algorithm Mertens function step by step in the 360 Assembly programming language