summaryrefslogtreecommitdiff
path: root/codegen/compiler.go
diff options
context:
space:
mode:
Diffstat (limited to 'codegen/compiler.go')
-rw-r--r--codegen/compiler.go75
1 files changed, 31 insertions, 44 deletions
diff --git a/codegen/compiler.go b/codegen/compiler.go
index 6f41850..48d3d41 100644
--- a/codegen/compiler.go
+++ b/codegen/compiler.go
@@ -9,24 +9,32 @@ import (
)
type symbol struct {
- index int // address of symbol in frame
- local bool // if true address is relative to local frame, otherwise global
+ index int // address of symbol in frame
+ local bool // if true address is relative to local frame, otherwise global
+ node *parser.Node // symbol definition in AST
}
type Compiler struct {
Code [][]int64 // produced code, to fill VM with
Data []any // produced data, will be at the bottom of VM stack
- Entry int
+ Entry int // offset in Code to start execution from (skip function defintions)
- symbols map[string]symbol
+ symbols map[string]*symbol
}
-func NewCompiler() *Compiler { return &Compiler{symbols: map[string]symbol{}, Entry: -1} }
+func NewCompiler() *Compiler { return &Compiler{symbols: map[string]*symbol{}, Entry: -1} }
type nodedata struct {
ipstart, ipend, fsp int // CFG and symbol node annotations
}
+type extNode struct {
+ *Compiler
+ *parser.Node
+ anc *parser.Node // node ancestor
+ rank int // node rank in ancestor's children
+}
+
func (c *Compiler) CodeGen(node *parser.Node) (err error) {
notes := map[*parser.Node]*nodedata{} // AST node annotations for CFG, symbols, ...
scope := ""
@@ -41,13 +49,13 @@ func (c *Compiler) CodeGen(node *parser.Node) (err error) {
switch n.Kind {
case parser.FuncDecl:
fname := n.Child[0].Content()
- c.AddSym(len(c.Code), scope+fname, false)
+ c.addSym(len(c.Code), scope+fname, false, n)
scope = pushScope(scope, fname)
frameNode = append(frameNode, n)
fnote = notes[n]
for j, child := range n.Child[1].Child {
vname := child.Content()
- c.AddSym(-j-2, scope+vname, true)
+ c.addSym(-j-2, scope+vname, true, child)
fnote.fsp++
}
@@ -61,27 +69,18 @@ func (c *Compiler) CodeGen(node *parser.Node) (err error) {
}, func(n, a *parser.Node, k int) (ok bool) {
// Node post-order processing callback.
nd := notes[n]
+ x := extNode{c, n, a, k}
switch n.Kind {
case parser.AddOp:
c.Emit(n, vm1.Add)
case parser.CallExpr:
- if c.isExternalSymbol(n.Child[0].Content()) {
- // External call, using absolute addr in symtable
- c.Emit(n, vm1.CallX, int64(len(n.Child[1].Child)))
- break
- }
- // Internal call is always relative to instruction pointer.
- i, ok := c.symInt(n.Child[0].Content())
- if !ok {
- err = fmt.Errorf("invalid symbol %s", n.Child[0].Content())
- }
- c.Emit(n, vm1.Call, int64(i-len(c.Code)))
+ err = postCallExpr(x)
case parser.DefOp:
// Define operation, global vars only. TODO: on local frame too
- l := c.AddSym(nil, n.Child[0].Content(), false)
+ l := c.addSym(nil, n.Child[0].Content(), false, n)
c.Emit(n, vm1.Assign, int64(l))
case parser.FuncDecl:
@@ -98,7 +97,7 @@ func (c *Compiler) CodeGen(node *parser.Node) (err error) {
c.Emit(n, vm1.Fdup, int64(s.index))
} else if a != nil && a.Kind == parser.AssignOp {
c.Emit(n, vm1.Push, int64(s.index))
- } else if c.isExternalSymbol(ident) {
+ } else if _, ok := c.Data[s.index].(int); !ok {
c.Emit(n, vm1.Dup, int64(s.index))
}
}
@@ -116,10 +115,8 @@ func (c *Compiler) CodeGen(node *parser.Node) (err error) {
c.Emit(n, vm1.Push, v)
case error:
err = v
- return false
default:
err = fmt.Errorf("type not supported: %T\n", v)
- return false
}
case parser.ReturnStmt:
@@ -141,6 +138,10 @@ func (c *Compiler) CodeGen(node *parser.Node) (err error) {
c.Emit(n, vm1.Sub)
}
+ if err != nil {
+ return false
+ }
+
// TODO: Fix this temporary hack to compute an entry point
if c.Entry < 0 && len(scope) == 0 && n.Kind != parser.FuncDecl {
c.Entry = len(c.Code) - 1
@@ -153,14 +154,16 @@ func (c *Compiler) CodeGen(node *parser.Node) (err error) {
return
}
-func (c *Compiler) AddSym(v any, name string, local bool) int {
+func (c *Compiler) AddSym(v any, name string) int { return c.addSym(v, name, false, nil) }
+
+func (c *Compiler) addSym(v any, name string, local bool, n *parser.Node) int {
l := len(c.Data)
if local {
l = v.(int)
} else {
c.Data = append(c.Data, v)
}
- c.symbols[name] = symbol{index: l, local: local}
+ c.symbols[name] = &symbol{index: l, local: local, node: n}
return l
}
@@ -171,25 +174,9 @@ func (c *Compiler) Emit(n *parser.Node, op ...int64) int {
return l
}
-func (c *Compiler) isExternalSymbol(name string) bool {
- s, ok := c.symbols[name]
- if !ok {
- return false
- }
- _, isInt := c.Data[s.index].(int)
- return !isInt
-}
-
-func (c *Compiler) symInt(name string) (int, bool) {
- s, ok := c.symbols[name]
- if !ok {
- return 0, false
- }
- j, ok := c.Data[s.index].(int)
- if !ok {
- return 0, false
- }
- return j, true
+func (c *Compiler) codeIndex(s *symbol) (i int, ok bool) {
+ i, ok = c.Data[s.index].(int)
+ return
}
func pushScope(scope, name string) string {
@@ -206,7 +193,7 @@ func popScope(scope string) string {
}
// getSym searches for an existing symbol starting from the deepest scope.
-func (c *Compiler) getSym(name, scope string) (sym symbol, sc string, ok bool) {
+func (c *Compiler) getSym(name, scope string) (sym *symbol, sc string, ok bool) {
for {
if sym, ok = c.symbols[scope+name]; ok {
return sym, scope, ok