Browse Source

Add boilerplate and basic IR generation

master
Forest Belton 2 years ago
parent
commit
444142a228
5 changed files with 153 additions and 10 deletions
  1. +44
    -0
      lib/ast.d.ts
  2. +52
    -1
      lib/compile.ts
  3. +46
    -0
      lib/ir.ts
  4. +4
    -2
      lib/parser.d.ts
  5. +7
    -7
      lib/parser.pegjs

+ 44
- 0
lib/ast.d.ts View File

@ -0,0 +1,44 @@
export type Program = Array<Decl | Stmt>
// Declarations
export type Decl = VarDecl
export type VarDecl = ADecl<"var", {
type: Type,
}>
type ADecl<Ty, Args> = {
type: "decl",
decl_type: Ty,
attrs: Array<Attr>,
name: string,
args: Args,
}
// Statements
export type Stmt = AssignStmt
export type AssignStmt = AStmt<"assign", {
name: string,
expr: Expr,
}>
type AStmt<Ty, Args> = {
type: "stmt",
stmt_type: Ty,
args: Args,
}
// Expressions
export type Expr = number
// Attributes
export type Attr = {
name: string,
args: Array<string | number>,
}
// Types
export type Type = PrimitiveType
export type PrimitiveType = "s8" | "u8" | "u16"

+ 52
- 1
lib/compile.ts View File

@ -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<Attr>,
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<Decl>): 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,
}
}

+ 46
- 0
lib/ir.ts View File

@ -0,0 +1,46 @@
import type { AssignStmt, Expr, Stmt } from "./ast"
// dest <- op(x, y)
type Operand = string | number
type ASSA<Data> = { 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<SSA>
}
export const convertIR = (stmts: Array<Stmt>): Array<SSA> => {
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<SSA> => {
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<SSA>] => {
const name = `temp${state.nextID++}`
return [name, [{ dest: name, source: expr }]]
}

+ 4
- 2
lib/parser.d.ts View File

@ -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

+ 7
- 7
lib/parser.pegjs View File

@ -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) }

Loading…
Cancel
Save