A "high-level" language for the Gameboy
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
2.4 KiB

  1. import type { AssignStmt, Expr, Stmt } from "./ast"
  2. type Operand = string | number
  3. type ASSA<Data> = { dest: string, source: Operand } & Data
  4. export type SSACopy = ASSA<{ source: Operand }> // dest = source
  5. export type SSAUnary = ASSA<{ op: string }> // dest = op(source)
  6. export type SSABinary = ASSA<{ op: string, source1: Operand }> // dest = op(source, source1)
  7. export type SSA = SSACopy | SSAUnary | SSABinary
  8. type IRState = {
  9. nextID: number
  10. ssa_stmts: Array<SSA>
  11. }
  12. export const convertIR = (stmts: Array<Stmt>): Array<SSA> => {
  13. const state: IRState = {
  14. nextID: 0,
  15. ssa_stmts: [],
  16. }
  17. stmts.forEach(stmt => {
  18. const ssa_stmts = convertAssignStmt(state, stmt)
  19. state.ssa_stmts.push(...ssa_stmts)
  20. })
  21. return state.ssa_stmts
  22. }
  23. export const convertAssignStmt = (state: IRState, stmt: AssignStmt): Array<SSA> => {
  24. return convertExpr(state, stmt.args.name, stmt.args.expr)
  25. }
  26. export const convertExpr = (state: IRState, dest: string, expr: Expr): Array<SSA> => {
  27. let expr_stmts = []
  28. if (typeof expr === "number" || typeof expr === "string") {
  29. expr_stmts = [{ dest, source: expr }]
  30. } else if (expr.type === "unary") {
  31. const [source, stmts] = getSource(state, expr.arg)
  32. stmts.push({
  33. dest,
  34. op: expr.op,
  35. source,
  36. })
  37. expr_stmts = stmts
  38. } else {
  39. const [left_source, left_stmts] = getSource(state, expr.left)
  40. const [right_source, right_stmts] = getSource(state, expr.right)
  41. const stmts = [...left_stmts, ...right_stmts]
  42. stmts.push({
  43. dest,
  44. op: expr.op,
  45. source: left_source,
  46. source1: right_source,
  47. })
  48. expr_stmts = stmts
  49. }
  50. return expr_stmts
  51. }
  52. const getSource = (state: IRState, expr: Expr): [string | number, Array<SSA>] => {
  53. if (typeof expr === "number" || typeof expr === "string") {
  54. return [expr, []]
  55. }
  56. const source = `temp${state.nextID++}`
  57. const stmts = convertExpr(state, source, expr)
  58. return [source, stmts]
  59. }
  60. export const prettyPrintIR = (ssa: SSA): string => {
  61. let output = ""
  62. if ("source1" in ssa) {
  63. output = `${ssa.dest} = ${ssa.op}(${ssa.source}, ${ssa.source1})`
  64. } else if ("op" in ssa) {
  65. output = `${ssa.dest} = ${ssa.op}(${ssa.source})`
  66. } else {
  67. output = `${ssa.dest} = ${ssa.source}`
  68. }
  69. return output
  70. }