Implemented block instruction parsing
This commit is contained in:
parent
4fc1935183
commit
dd495fab4e
@ -8,5 +8,7 @@ hello() {
|
||||
address := 4194305
|
||||
length := 3
|
||||
|
||||
syscall(write, stdout, address, length)
|
||||
loop {
|
||||
syscall(write, stdout, address, length)
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
@ -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++
|
||||
}
|
||||
}
|
||||
|
@ -3,4 +3,5 @@ package token
|
||||
// Keywords defines the keywords used in the language.
|
||||
var Keywords = map[string]bool{
|
||||
"return": true,
|
||||
"loop": true,
|
||||
}
|
||||
|
@ -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{}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user