From 444142a2281a3eed12a84aec77e66f62f5907091 Mon Sep 17 00:00:00 2001 From: Forest Belton Date: Mon, 13 Sep 2021 20:41:40 -0400 Subject: [PATCH] Add boilerplate and basic IR generation --- lib/ast.d.ts | 44 ++++++++++++++++++++++++++++++++++++++++ lib/compile.ts | 53 +++++++++++++++++++++++++++++++++++++++++++++++- lib/ir.ts | 46 +++++++++++++++++++++++++++++++++++++++++ lib/parser.d.ts | 6 ++++-- lib/parser.pegjs | 14 ++++++------- 5 files changed, 153 insertions(+), 10 deletions(-) create mode 100644 lib/ast.d.ts create mode 100644 lib/ir.ts diff --git a/lib/ast.d.ts b/lib/ast.d.ts new file mode 100644 index 0000000..e8e6030 --- /dev/null +++ b/lib/ast.d.ts @@ -0,0 +1,44 @@ +export type Program = Array + +// Declarations +export type Decl = VarDecl + +export type VarDecl = ADecl<"var", { + type: Type, +}> + +type ADecl = { + type: "decl", + decl_type: Ty, + attrs: Array, + name: string, + args: Args, +} + +// Statements +export type Stmt = AssignStmt + +export type AssignStmt = AStmt<"assign", { + name: string, + expr: Expr, +}> + +type AStmt = { + type: "stmt", + stmt_type: Ty, + args: Args, +} + +// Expressions +export type Expr = number + +// Attributes +export type Attr = { + name: string, + args: Array, +} + +// Types +export type Type = PrimitiveType + +export type PrimitiveType = "s8" | "u8" | "u16" diff --git a/lib/compile.ts b/lib/compile.ts index b5d41f4..04c23e7 100644 --- a/lib/compile.ts +++ b/lib/compile.ts @@ -1,9 +1,60 @@ import { parse } from "./parser" +import { convertIR } from "./ir" +import type { Attr, Decl, Stmt, Type, VarDecl } from "./ast" +type SymbolDefn = { + attrs: Array, + name: string, + type: Type +} + +type SymbolMap = { + [name: string]: SymbolDefn +} + +// TODO: Support more than one TU export const compile = (source: string): string => { // 1. Parse const ast = parse(source) - console.log(ast) + + // 2. Partition declarations and statements + const decls = ast.filter((x): x is Decl => x.type == "decl") + const stmts = ast.filter((x): x is Stmt => x.type == "stmt") + + console.log("Declarations", decls) + console.log("Statements", stmts) + + // 3. Create top-level symbol map + const symbols = processDecls(decls) + + console.log("Symbols", symbols) + + // TODO: Some form of type-checking + + // 4. Generate IR + const ir = convertIR(stmts) + + console.log("IR", ir) return "" } + +export const processDecls = (decls: Array): SymbolMap => decls.reduce((symbols, decl) => { + const symbol = processVarDecl(symbols, decl) + return { + ...symbols, + [symbol.name]: symbol, + } +}, {}) + +export const processVarDecl = (symbols: SymbolMap, decl: VarDecl): SymbolDefn => { + if (typeof symbols[decl.name] !== 'undefined') { + throw new Error(`a variable named \`${decl.name}' is already defined`) + } + + return { + attrs: decl.attrs, + name: decl.name, + type: decl.args.type, + } +} diff --git a/lib/ir.ts b/lib/ir.ts new file mode 100644 index 0000000..3909b7d --- /dev/null +++ b/lib/ir.ts @@ -0,0 +1,46 @@ +import type { AssignStmt, Expr, Stmt } from "./ast" + +// dest <- op(x, y) +type Operand = string | number + +type ASSA = { dest: string } & Data + +type SSA = ASSA<{ source: Operand }> + | ASSA<{ source: Operand, op: string }> + | ASSA<{ source1: Operand, op: string, source2: Operand }> + +type IRState = { + nextID: number + ssa_stmts: Array +} + +export const convertIR = (stmts: Array): Array => { + const state: IRState = { + nextID: 0, + ssa_stmts: [], + } + + stmts.forEach(stmt => { + const ssa_stmts = convertAssignStmt(state, stmt) + state.ssa_stmts.push(...ssa_stmts) + }) + + return state.ssa_stmts +} + +export const convertAssignStmt = (state: IRState, stmt: AssignStmt): Array => { + const dest = stmt.args.name + const [source, expr_stmts] = convertExpr(state, stmt.args.expr) + + expr_stmts.push({ + dest, + source, + }) + + return expr_stmts +} + +export const convertExpr = (state: IRState, expr: Expr): [string, Array] => { + const name = `temp${state.nextID++}` + return [name, [{ dest: name, source: expr }]] +} diff --git a/lib/parser.d.ts b/lib/parser.d.ts index d559aee..30da397 100644 --- a/lib/parser.d.ts +++ b/lib/parser.d.ts @@ -1,3 +1,5 @@ -export const SyntaxError: any; +import type { Program } from "./ast" -export function parse(input: string): any; +export const SyntaxError: any + +export function parse(input: string): Program diff --git a/lib/parser.pegjs b/lib/parser.pegjs index ec73565..b929f71 100644 --- a/lib/parser.pegjs +++ b/lib/parser.pegjs @@ -2,27 +2,23 @@ { const attr = (name, args) => ({ name, args }) const stmt = (stmt_type, args) => ({ type: "stmt", stmt_type, args }) - const decl = (decl_type, args) => ({ type: "decl", decl_type, args }) + const decl = (decl_type, name, attrs, args) => ({ type: "decl", decl_type, name, attrs: attrs || [], args }) } Program = WS @(Decl / Stmt)* WS // Declarations Decl = VarDecl -VarDecl = Attrs? type:Type name:Ident SEMI { return decl("var", { type, name }) } +VarDecl = attrs:Attrs? type:Type name:Ident SEMI { return decl("var", name, attrs, { type }) } // Statements Stmt = @AssignStmt SEMI AssignStmt = name:Ident ASSIGN expr:Expr { return stmt("assign", { name, expr }) } -// Expr +// Expressions Expr = BaseExpr BaseExpr = Number -// Primitive types -Type = PrimitiveType -PrimitiveType = S8 / U8 / U16 - // Attributes Attrs = LATTR @AttrList RATTR AttrList = h:Attr t:(COMMA @Attr)* { return [h].concat(t) } @@ -32,6 +28,10 @@ AttrArgs = h:AttrArg t:(COMMA @AttrArg)* { return [h].concat(t) } / '' { return [] } AttrArg = Ident / Number +// Types +Type = PrimitiveType +PrimitiveType = S8 / U8 / U16 + // Terminals Ident = h:[a-zA-Z_] t:[0-9a-zA-Z_]* WS { return h + t.join('') } Number = digits:[0-9]+ WS { return parseInt(digits.join(''), 10) }