4 Commits

6 changed files with 221 additions and 24 deletions
Split View
  1. +1
    -2
      example.gby
  2. +49
    -0
      lib/asm.ts
  3. +8
    -1
      lib/ast.d.ts
  4. +97
    -0
      lib/graph/graph.ts
  5. +36
    -19
      lib/ir.ts
  6. +30
    -2
      lib/parser.pegjs

+ 1
- 2
example.gby View File

@ -1,5 +1,4 @@
u8 x;
u8 y;
x <- 1;
y <- -x;
x <- -y + 3;

+ 49
- 0
lib/asm.ts View File

@ -106,6 +106,55 @@ const convertASM_SSA = (state: ASMState, ssa: SSA): void => {
export const convertASM_SSA_Binary = (state: ASMState, ssa: SSABinary): void => {
const dest = state.alloc_sym_loc(ssa.dest)
if (typeof ssa.source === "number") {
state.insns.push(`LD A, ${ssa.source}`)
} else {
const loc = state.get_sym_loc(ssa.source)
if (loc === null) {
state.insns.push(`LD A, (${ssa.source})`)
} else if (typeof loc === "string") {
state.insns.push(`LD A, ${loc}`)
} else {
state.insns.push(
`LD HL, SP + (${loc})`,
`LD A, (HL)`
)
}
}
switch (ssa.op) {
case "add":
if (typeof ssa.source1 === "number") {
state.insns.push(`ADD ${ssa.source1}`)
} else {
const loc = state.get_sym_loc(ssa.source1)
if (loc === null) {
throw new Error('fuck')
} else if (typeof loc === "string") {
state.insns.push(`ADD ${loc}`)
} else {
throw new Error('fuck')
state.insns.push(
`LD HL, SP + (${loc})`
)
}
}
break
default:
throw new Error(`unsupported binary op \`${ssa.op}'`)
}
if (typeof dest === "string") {
state.insns.push(`LD ${dest}, A`)
} else {
state.insns.push(
`LD HL, SP + (${dest})`,
`LD (HL), A`
)
}
}
export const convertASM_SSA_Unary = (state: ASMState, ssa: SSAUnary): void => {

+ 8
- 1
lib/ast.d.ts View File

@ -30,7 +30,14 @@ type AStmt = {
}
// Expressions
export type Expr = UnaryExpr | BasicExpr
export type Expr = BinaryExpr | UnaryExpr | BasicExpr
type BinaryExpr = {
type: "binary",
op: string,
left: Expr,
right: Expr,
}
type UnaryExpr = {
type: "unary",

+ 97
- 0
lib/graph/graph.ts View File

@ -0,0 +1,97 @@
export type Graph<V> = {
vertices: {
[v: string]: V
},
edges: {
[v: string]: Set<string>
}
}
export type AddVertex<V> = (name: string, v: V) => void
export type AddEdge = (source: string, dest: string) => void
export const createGraph = <V>(cons: (v: AddVertex<V>, e: AddEdge) => void): Graph<V> => {
const g: Graph<V> = { vertices: {}, edges: {} }
const addVertex = (name: string, v: V) => {
g.vertices[name] = v
g.edges[name] = new Set()
}
const addEdge = (source: string, dest: string) => {
if (typeof g.vertices[source] === "undefined") {
throw new Error(`vertex \`${source}' does not exist in graph`)
} else if (typeof g.vertices[dest] === "undefined") {
throw new Error(`vertex \`${dest}' does not exist in graph`)
}
g.edges[source].add(dest)
g.edges[dest].add(source)
}
cons(addVertex, addEdge)
return g
}
export const neighbors = <V>(g: Graph<V>, name: string): Set<string> => {
if (typeof g.vertices[name] === "undefined") {
throw new Error(`vertex \`${name}' does not exist in graph`)
}
return g.edges[name]
}
export const vertices = <V>(g: Graph<V>): Set<string> => new Set(Object.keys(g.vertices))
export const maxCardinalitySearch = <V>(g: Graph<V>): Array<string> => {
const weights: { [s: string]: number } = {}
const ordering: Array<string> = []
let W = vertices(g)
const numVertices = W.size
for (let i = 0; i < numVertices; ++i) {
const v = findMaxWeight(weights, W)
ordering.push(v)
setIntersect(W, neighbors(g, v)).forEach(x =>
weights[x] = (weights[x] || 0) + 1
)
W.delete(v)
}
return ordering
}
const findMaxWeight = (weights: { [s: string]: number }, W: Set<string>): string => {
let maxV = null
let maxWeight = -Infinity
W.forEach(v => {
const vWeight = weights[v] || 0
if (vWeight > maxWeight) {
maxV = v
maxWeight = vWeight
}
})
if (maxV === null) {
throw new Error(`remaining vertex set is empty`)
}
return maxV
}
const setIntersect = <A>(xs: Set<A>, ys: Set<A>): Set<A> => {
const intersection: Set<A> = new Set()
xs.forEach(x => {
if (ys.has(x)) {
intersection.add(x)
}
})
return intersection
}

+ 36
- 19
lib/ir.ts View File

@ -32,41 +32,58 @@ export const convertIR = (stmts: Array): Array => {
}
export const convertAssignStmt = (state: IRState, stmt: AssignStmt): Array<SSA> => {
const dest = stmt.args.name
const [source, expr_stmts] = convertExpr(state, stmt.args.expr)
return convertExpr(state, stmt.args.name, stmt.args.expr)
}
expr_stmts.push({
dest,
source,
})
export const convertExpr = (state: IRState, dest: string, expr: Expr): Array<SSA> => {
let expr_stmts = []
if (typeof expr === "number" || typeof expr === "string") {
expr_stmts = [{ dest, source: expr }]
} else if (expr.type === "unary") {
const [source, stmts] = getSource(state, expr.arg)
stmts.push({
dest,
op: expr.op,
source,
})
expr_stmts = stmts
} else {
const [left_source, left_stmts] = getSource(state, expr.left)
const [right_source, right_stmts] = getSource(state, expr.right)
const stmts = [...left_stmts, ...right_stmts]
stmts.push({
dest,
op: expr.op,
source: left_source,
source1: right_source,
})
expr_stmts = stmts
}
return expr_stmts
}
export const convertExpr = (state: IRState, expr: Expr): [string | number, Array<SSA>] => {
const getSource = (state: IRState, expr: Expr): [string | number, Array<SSA>] => {
if (typeof expr === "number" || typeof expr === "string") {
return [expr, []]
}
const [source, expr_stmts] = convertExpr(state, expr.arg)
const name = `temp${state.nextID++}`
expr_stmts.push({
dest: name,
source,
op: expr.op,
})
return [name, expr_stmts]
const source = `temp${state.nextID++}`
const stmts = convertExpr(state, source, expr)
return [source, stmts]
}
export const prettyPrintIR = (ssa: SSA): string => {
let output = ""
if ("source1" in ssa) {
output = `${ssa.dest} = ${ssa.source} ${ssa.op} ${ssa.source1}`
output = `${ssa.dest} = ${ssa.op}(${ssa.source}, ${ssa.source1})`
} else if ("op" in ssa) {
output = `${ssa.dest} = ${ssa.op} ${ssa.source}`
output = `${ssa.dest} = ${ssa.op}(${ssa.source})`
} else {
output = `${ssa.dest} = ${ssa.source}`
}

+ 30
- 2
lib/parser.pegjs View File

@ -4,7 +4,12 @@
const stmt = (stmt_type, args) => ({ type: "stmt", stmt_type, args })
const decl = (decl_type, name, attrs, args) => ({ type: "decl", decl_type, name, attrs: attrs || [], args })
const uexpr = (op, arg) => ({ type: "unary", op, arg })
const bexpr = (op, arg1, arg2) => ({ type: "binary", op, arg1, arg2 })
const bexpr = (op, left, right) => ({ type: "binary", op, left, right })
const assocl = (head, tail) => tail.reduce((left, arg) => {
const [op, right] = arg
return bexpr(op, left, right)
}, head)
}
Program = WS @(Decl / Stmt)* WS
@ -18,7 +23,24 @@ Stmt = @AssignStmt SEMI
AssignStmt = name:Ident ASSIGN expr:Expr { return stmt("assign", { name, expr }) }
// Expressions
Expr = UnaryExpr
Expr = BitOrExpr
BitOrExpr = head:BitXorExpr tail:(op:BitOrOp e:BitXorExpr)* { return assocl(head, tail || []) }
BitOrOp = PIPE { return "bit_or" }
BitXorExpr = head:BitAndExpr tail:(op:BitXorOp e:BitAndExpr)* { return assocl(head, tail || []) }
BitXorOp = CARET { return "bit_xor" }
BitAndExpr = head:ShiftExpr tail:(op:BitAndOp e:ShiftExpr)* { return assocl(head, tail || []) }
BitAndOp = AMPERSAND { return "bit_and" }
ShiftExpr = head:AddExpr tail:(op:ShiftOp e:AddExpr)* { return assocl(head, tail || []) }
ShiftOp = LTLT { return "shift_left" }
/ GTGT { return "shift_right" }
AddExpr = head:UnaryExpr tail:(op:AddOp e:UnaryExpr)* { return assocl(head, tail || []) }
AddOp = PLUS { return "add" }
/ MINUS { return "subtract" }
UnaryExpr = op:UnaryOp? e:BaseExpr { return op ? uexpr(op, e) : e }
UnaryOp = TILDE { return "bit_negate" }
@ -51,6 +73,12 @@ U8 = @'u8' WS
U16 = @'u16' WS
// Terminal symbols
PIPE = '|' WS
CARET = '^' WS
AMPERSAND = '&' WS
LTLT = '<<' WS
GTGT = '>>' WS
PLUS = '+' WS
TILDE = '~' WS
MINUS = '-' WS
SEMI = ';' WS

Loading…
Cancel
Save