From dd495fab4ef4fddde943e1827504a0f600e534a1 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Mon, 24 Jun 2024 00:03:26 +0200 Subject: [PATCH] Implemented block instruction parsing --- examples/hello/hello.q | 4 +++- src/build/Function.go | 48 ++++++++++++++++++++++++++++++------- src/build/scan.go | 4 ++-- src/build/token/Keywords.go | 1 + src/build/token/List.go | 22 +++++++++++++++++ src/build/token/Token.go | 4 ++-- 6 files changed, 70 insertions(+), 13 deletions(-) diff --git a/examples/hello/hello.q b/examples/hello/hello.q index 60f65e4..a9ef287 100644 --- a/examples/hello/hello.q +++ b/examples/hello/hello.q @@ -8,5 +8,7 @@ hello() { address := 4194305 length := 3 - syscall(write, stdout, address, length) + loop { + syscall(write, stdout, address, length) + } } \ No newline at end of file diff --git a/src/build/Function.go b/src/build/Function.go index efdac96..7cffba6 100644 --- a/src/build/Function.go +++ b/src/build/Function.go @@ -28,28 +28,40 @@ type Function struct { // Compile turns a function into machine code. func (f *Function) Compile() { 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 groupLevel := 0 + blockLevel := 0 - for i, t := range f.Body { - if start == i && (t.Kind == token.NewLine || t.Kind == token.BlockStart || t.Kind == token.BlockEnd) { + for i, t := range body { + if start == i && t.Kind == token.NewLine { start = i + 1 continue } switch t.Kind { case token.NewLine: - if groupLevel > 0 { + if groupLevel > 0 || blockLevel > 0 { continue } if start != -1 { - instruction := f.Body[start:i] + instruction := body[start:i] err := f.CompileInstruction(instruction) if err != nil { - f.Error = err - return + return err } start = -1 @@ -62,10 +74,16 @@ func (f *Function) Compile() { case token.GroupEnd: groupLevel-- + + case token.BlockStart: + blockLevel++ + + case token.BlockEnd: + blockLevel-- } } - f.Assembler.Return() + return nil } // CompileInstruction compiles a single instruction. @@ -109,6 +127,20 @@ func (f *Function) CompileKeyword(line token.List) error { 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: 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. func (f *Function) CompileVariableDefinition(expr *expression.Expression) error { 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() diff --git a/src/build/scan.go b/src/build/scan.go index 219c132..a78ce93 100644 --- a/src/build/scan.go +++ b/src/build/scan.go @@ -192,12 +192,11 @@ func scanFile(path string, functions chan<- *Function) error { return errors.New(errors.MissingBlockStart, file, tokens[i].Position) } - i++ - if blockLevel == 0 { break } + i++ continue } @@ -237,5 +236,6 @@ func scanFile(path string, functions chan<- *Function) error { nameStart = -1 paramsStart = -1 bodyStart = -1 + i++ } } diff --git a/src/build/token/Keywords.go b/src/build/token/Keywords.go index adb8de7..d5f6231 100644 --- a/src/build/token/Keywords.go +++ b/src/build/token/Keywords.go @@ -3,4 +3,5 @@ package token // Keywords defines the keywords used in the language. var Keywords = map[string]bool{ "return": true, + "loop": true, } diff --git a/src/build/token/List.go b/src/build/token/List.go index be3a1ff..1b725b6 100644 --- a/src/build/token/List.go +++ b/src/build/token/List.go @@ -7,6 +7,28 @@ import ( // List is a slice of tokens. 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. func (list List) String() string { builder := bytes.Buffer{} diff --git a/src/build/token/Token.go b/src/build/token/Token.go index 66c77b1..fadf760 100644 --- a/src/build/token/Token.go +++ b/src/build/token/Token.go @@ -11,8 +11,8 @@ type Token struct { Bytes []byte } -// After returns the position after the token. -func (t *Token) After() int { +// End returns the position after the token. +func (t *Token) End() int { return t.Position + len(t.Bytes) }