Implemented block instruction parsing

This commit is contained in:
Eduard Urbach 2024-06-24 00:03:26 +02:00
parent 4fc1935183
commit dd495fab4e
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
6 changed files with 70 additions and 13 deletions

View File

@ -8,5 +8,7 @@ hello() {
address := 4194305 address := 4194305
length := 3 length := 3
loop {
syscall(write, stdout, address, length) syscall(write, stdout, address, length)
}
} }

View File

@ -28,28 +28,40 @@ type Function struct {
// Compile turns a function into machine code. // Compile turns a function into machine code.
func (f *Function) Compile() { func (f *Function) Compile() {
f.Assembler.Label(f.Name) f.Assembler.Label(f.Name)
err := f.CompileTokens(f.Body)
if err != nil {
f.Error = err
return
}
f.Assembler.Return()
}
// CompileTokens compiles a token list.
func (f *Function) CompileTokens(body token.List) error {
start := 0 start := 0
groupLevel := 0 groupLevel := 0
blockLevel := 0
for i, t := range f.Body { for i, t := range body {
if start == i && (t.Kind == token.NewLine || t.Kind == token.BlockStart || t.Kind == token.BlockEnd) { if start == i && t.Kind == token.NewLine {
start = i + 1 start = i + 1
continue continue
} }
switch t.Kind { switch t.Kind {
case token.NewLine: case token.NewLine:
if groupLevel > 0 { if groupLevel > 0 || blockLevel > 0 {
continue continue
} }
if start != -1 { if start != -1 {
instruction := f.Body[start:i] instruction := body[start:i]
err := f.CompileInstruction(instruction) err := f.CompileInstruction(instruction)
if err != nil { if err != nil {
f.Error = err return err
return
} }
start = -1 start = -1
@ -62,10 +74,16 @@ func (f *Function) Compile() {
case token.GroupEnd: case token.GroupEnd:
groupLevel-- groupLevel--
case token.BlockStart:
blockLevel++
case token.BlockEnd:
blockLevel--
} }
} }
f.Assembler.Return() return nil
} }
// CompileInstruction compiles a single instruction. // CompileInstruction compiles a single instruction.
@ -109,6 +127,20 @@ func (f *Function) CompileKeyword(line token.List) error {
f.Assembler.Return() f.Assembler.Return()
case "loop":
blockStart := line.IndexKind(token.BlockStart) + 1
blockEnd := line.LastIndexKind(token.BlockEnd)
if blockStart == -1 {
return errors.New(errors.MissingBlockStart, f.File, line[0].End())
}
if blockEnd == -1 {
return errors.New(errors.MissingBlockEnd, f.File, line[len(line)-1].End())
}
return f.CompileTokens(line[blockStart:blockEnd])
default: default:
return errors.New(&errors.KeywordNotImplemented{Keyword: line[0].Text()}, f.File, line[0].Position) return errors.New(&errors.KeywordNotImplemented{Keyword: line[0].Text()}, f.File, line[0].Position)
} }
@ -119,7 +151,7 @@ func (f *Function) CompileKeyword(line token.List) error {
// CompileVariableDefinition compiles a variable definition. // CompileVariableDefinition compiles a variable definition.
func (f *Function) CompileVariableDefinition(expr *expression.Expression) error { func (f *Function) CompileVariableDefinition(expr *expression.Expression) error {
if len(expr.Children) < 2 { if len(expr.Children) < 2 {
return errors.New(errors.MissingAssignValue, f.File, expr.LastChild().Token.After()) return errors.New(errors.MissingAssignValue, f.File, expr.LastChild().Token.End())
} }
name := expr.Children[0].Token.Text() name := expr.Children[0].Token.Text()

View File

@ -192,12 +192,11 @@ func scanFile(path string, functions chan<- *Function) error {
return errors.New(errors.MissingBlockStart, file, tokens[i].Position) return errors.New(errors.MissingBlockStart, file, tokens[i].Position)
} }
i++
if blockLevel == 0 { if blockLevel == 0 {
break break
} }
i++
continue continue
} }
@ -237,5 +236,6 @@ func scanFile(path string, functions chan<- *Function) error {
nameStart = -1 nameStart = -1
paramsStart = -1 paramsStart = -1
bodyStart = -1 bodyStart = -1
i++
} }
} }

View File

@ -3,4 +3,5 @@ package token
// Keywords defines the keywords used in the language. // Keywords defines the keywords used in the language.
var Keywords = map[string]bool{ var Keywords = map[string]bool{
"return": true, "return": true,
"loop": true,
} }

View File

@ -7,6 +7,28 @@ import (
// List is a slice of tokens. // List is a slice of tokens.
type List []Token type List []Token
// IndexKind returns the position of a token kind within a token list.
func (list List) IndexKind(kind Kind) int {
for i, token := range list {
if token.Kind == kind {
return i
}
}
return -1
}
// LastIndexKind returns the position of the last token kind within a token list.
func (list List) LastIndexKind(kind Kind) int {
for i := len(list) - 1; i >= 0; i-- {
if list[i].Kind == kind {
return i
}
}
return -1
}
// String implements string serialization. // String implements string serialization.
func (list List) String() string { func (list List) String() string {
builder := bytes.Buffer{} builder := bytes.Buffer{}

View File

@ -11,8 +11,8 @@ type Token struct {
Bytes []byte Bytes []byte
} }
// After returns the position after the token. // End returns the position after the token.
func (t *Token) After() int { func (t *Token) End() int {
return t.Position + len(t.Bytes) return t.Position + len(t.Bytes)
} }