/
lower.go
91 lines (87 loc) · 2.81 KB
/
lower.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package bf
import (
"fmt"
"go/token"
"math/big"
"github.com/andrewarchi/nebula/ir"
)
type bracketBlock struct {
Block *ir.BasicBlock
Pos token.Pos
}
// LowerIR lowers a Brainfuck program to Nebula IR in SSA form.
func (p *Program) LowerIR() (*ir.Program, []error) {
b := ir.NewBuilder(p.File)
b.SetCurrentBlock(b.CreateBlock())
dataPtr := ir.NewIntConst(big.NewInt(0), token.NoPos)
one := ir.NewIntConst(big.NewInt(1), token.NoPos)
b.CreateStoreHeapStmt(dataPtr, one, token.NoPos)
var bracketStack []bracketBlock
var errs []error
for _, tok := range p.Tokens {
switch tok.Type {
case IncPtr:
load := b.CreateLoadHeapExpr(dataPtr, tok.Pos)
inc := b.CreateBinaryExpr(ir.Add, load, one, tok.Pos)
b.CreateStoreHeapStmt(dataPtr, inc, tok.Pos)
case DecPtr:
load := b.CreateLoadHeapExpr(dataPtr, tok.Pos)
dec := b.CreateBinaryExpr(ir.Sub, load, one, tok.Pos)
b.CreateStoreHeapStmt(dataPtr, dec, tok.Pos)
case IncData:
data := b.CreateLoadHeapExpr(dataPtr, tok.Pos)
val := b.CreateLoadHeapExpr(data, tok.Pos)
inc := b.CreateBinaryExpr(ir.Add, val, one, tok.Pos)
b.CreateStoreHeapStmt(data, inc, tok.Pos)
case DecData:
data := b.CreateLoadHeapExpr(dataPtr, tok.Pos)
val := b.CreateLoadHeapExpr(data, tok.Pos)
dec := b.CreateBinaryExpr(ir.Sub, val, one, tok.Pos)
b.CreateStoreHeapStmt(data, dec, tok.Pos)
case Print:
data := b.CreateLoadHeapExpr(dataPtr, tok.Pos)
val := b.CreateLoadHeapExpr(data, tok.Pos)
b.CreatePrintStmt(ir.PrintByte, val, tok.Pos)
case Read:
val := b.CreateReadExpr(ir.ReadByte, tok.Pos)
data := b.CreateLoadHeapExpr(dataPtr, tok.Pos)
b.CreateStoreHeapStmt(data, val, tok.Pos)
case Bracket:
if len(b.CurrentBlock().Nodes) != 0 {
head := b.CreateBlock()
b.CreateJmpTerm(ir.Fallthrough, head, tok.Pos)
b.SetCurrentBlock(head)
}
data := b.CreateLoadHeapExpr(dataPtr, tok.Pos)
val := b.CreateLoadHeapExpr(data, tok.Pos)
next := b.CreateBlock()
b.CreateJmpCondTerm(ir.Jz, val, nil, next, tok.Pos)
bracketStack = append(bracketStack, bracketBlock{b.CurrentBlock(), tok.Pos})
b.SetCurrentBlock(next)
case EndBracket:
if len(bracketStack) == 0 {
errs = append(errs, fmt.Errorf("End bracket not matched at %v", tok.Pos))
continue
}
head := bracketStack[len(bracketStack)-1].Block
bracketStack = bracketStack[:len(bracketStack)-1]
next := b.CreateBlock()
head.Terminator.(*ir.JmpCondTerm).Succs()[0] = next
b.CreateJmpTerm(ir.Jmp, head, tok.Pos)
b.SetCurrentBlock(next)
}
}
exitPos := token.NoPos
if len(p.Tokens) != 0 {
exitPos = p.Tokens[len(p.Tokens)-1].Pos
}
b.CreateExitTerm(exitPos)
for _, bracket := range bracketStack {
errs = append(errs, fmt.Errorf("Bracket not matched at %v", bracket.Pos))
}
ssa, err := b.Program()
if err != nil {
errs = append(errs, err)
}
return ssa, errs
}