Example #1
0
File: asm.go Project: DanB91/dcpu
// buildFunction compiles the given function.
func (a *assembler) buildFunction(f *parser.Function) (err error) {
	nodes := f.Children()
	name := nodes[0].(*parser.Label)

	a.debug.SetFunctionStart(cpu.Word(len(a.code)), f.Line(), name.Data)

	for i := range nodes {
		switch tt := nodes[i].(type) {
		case *parser.Comment:
			/* ignore */

		case *parser.Label:
			a.labels[tt.Data] = cpu.Word(len(a.code))

		case *parser.Instruction:
			err = a.buildInstruction(tt.Children())

		default:
			err = NewBuildError(
				a.ast.Files[tt.File()], tt.Line(), tt.Col(),
				"Unexpected node %T. Want Comment, Label, Instruction.", tt,
			)
		}

		if err != nil {
			return
		}
	}

	a.debug.SetFunctionEnd(cpu.Word(len(a.code)), nodes[len(nodes)-1].Line())
	return
}
Example #2
0
File: funcs.go Project: DanB91/dcpu
func parseFuncConst(ast *parser.AST, f *parser.Function) (err error) {
	list, err := parseConstants(ast, f.Children())
	if err != nil {
		return
	}

	f.SetChildren(list)
	return
}
Example #3
0
func (sw *SourceWriter) writeFunction(n *parser.Function) {
	var name string
	chld := n.Children()

	switch tt := chld[0].(type) {
	case *parser.Name:
		name = tt.Data
	case *parser.Label:
		name = tt.Data
	}

	fmt.Fprintf(sw.w, "def %s\n", name)
	sw.writeList(chld[1:])
	sw.w.Write([]byte("end"))
}
Example #4
0
File: funcs.go Project: DanB91/dcpu
// fixFunctionReturns finds 'return' instructions and replaces them
// with appropriate `set pc, $__<name>_epilog` versions.
func fixFunctionReturns(ast *parser.AST, f *parser.Function) {
	var instr *parser.Instruction
	var expr *parser.Expression
	var file, line, col int
	var code []parser.Node
	var ok bool

	name := f.Children()[0].(*parser.Name)
	exitLabel := "$__" + name.Data + "_epilog"
	list := f.Children()[1:]

	for i := range list {
		if instr, ok = list[i].(*parser.Instruction); !ok {
			continue
		}

		code = instr.Children()
		name = code[0].(*parser.Name)
		if name.Data != "return" {
			continue
		}

		file, line, col = instr.File(), instr.Line(), instr.Col()
		name.Data = "set"
		code = append(code, nil, nil)

		expr = parser.NewExpression(file, line, col)
		expr.SetChildren([]parser.Node{
			parser.NewName(file, line, col, "pc"),
		})
		code[1] = expr

		expr = parser.NewExpression(file, line, col)
		expr.SetChildren([]parser.Node{
			parser.NewName(file, line, col, exitLabel),
		})
		code[2] = expr

		instr.SetChildren(code)
	}
}
Example #5
0
File: funcs.go Project: DanB91/dcpu
// injectFunctionCode injects function prologs and epilogs.
func injectFunctionCode(ast *parser.AST, f *parser.Function) {
	var tmp, code []parser.Node
	var instr *parser.Instruction
	var expr *parser.Expression
	var idx int

	name := f.Children()[0].(*parser.Name)
	exitLabel := "$__" + name.Data + "_epilog"
	file, line, col := name.File(), name.Line(), name.Col()

	// Find list of referenced protected registers.
	var regs []string
	findProtectedRegisters(f.Children()[1:], &regs)

	// Inject prolog and epilog code.
	//
	// For each protected register we found, we add appropriate
	// stack push/pop instructions to preserve their state.
	tmp = make([]parser.Node, len(f.Children())+(len(regs)*2)+2)
	tmp[idx] = parser.NewLabel(file, line, col, name.Data)
	idx++

	// set push, $reg
	for n := range regs {
		instr = parser.NewInstruction(file, line, col)
		code = make([]parser.Node, 3)
		code[0] = parser.NewName(file, line, col, "set")

		expr = parser.NewExpression(file, line, col)
		expr.SetChildren([]parser.Node{
			parser.NewName(file, line, col, "push"),
		})
		code[1] = expr

		expr = parser.NewExpression(file, line, col)
		expr.SetChildren([]parser.Node{
			parser.NewName(file, line, col, regs[n]),
		})
		code[2] = expr

		instr.SetChildren(code)
		tmp[idx] = instr
		idx++
	}

	// Regular code goes here.
	copy(tmp[idx:], f.Children()[1:])
	idx += len(f.Children()) - 1

	// Label denoting the start of the epilog.
	line, col = tmp[idx-1].Line()+1, 1
	tmp[idx] = parser.NewLabel(file, line, col, exitLabel)
	idx++

	// set $reg, pop
	for n := range regs {
		instr = parser.NewInstruction(file, line, col)
		code = make([]parser.Node, 3)
		code[0] = parser.NewName(file, line, col, "set")

		expr = parser.NewExpression(file, line, col)
		expr.SetChildren([]parser.Node{
			parser.NewName(file, line, col, regs[n]),
		})
		code[1] = expr

		expr = parser.NewExpression(file, line, col)
		expr.SetChildren([]parser.Node{
			parser.NewName(file, line, col, "pop"),
		})
		code[2] = expr

		instr.SetChildren(code)
		tmp[idx] = instr
		idx++
	}

	// set pc, pop
	instr = parser.NewInstruction(file, line, col)
	code = make([]parser.Node, 3)
	code[0] = parser.NewName(file, line, col, "set")

	expr = parser.NewExpression(file, line, col)
	expr.SetChildren([]parser.Node{
		parser.NewName(file, line, col, "pc"),
	})
	code[1] = expr

	expr = parser.NewExpression(file, line, col)
	expr.SetChildren([]parser.Node{
		parser.NewName(file, line, col, "pop"),
	})
	code[2] = expr

	instr.SetChildren(code)
	tmp[idx] = instr

	f.SetChildren(tmp)
}