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
length := 3
syscall(write, stdout, address, length)
loop {
syscall(write, stdout, address, length)
}
}

View File

@ -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()

View File

@ -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++
}
}

View File

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

View File

@ -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{}

View File

@ -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)
}