mirror of
https://github.com/hazemKrimi/jack-compiler.git
synced 2026-05-01 17:48:57 +00:00
feat: compile third test program
This commit is contained in:
@@ -32,6 +32,16 @@ func segmentFromVariableKind(kind table.VariableKind) code.Segment {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isMethodName(tokens []tokenizer.Token, identifier string) bool {
|
||||||
|
for index, token := range tokens {
|
||||||
|
if token.Value == identifier && index >= 2 && tokens[index-2].Value == "method" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func compileTerm(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
|
func compileTerm(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
|
||||||
if tokens[*index].Type == tokenizer.SYMBOL && slices.Contains([]string{"-", "~"}, tokens[*index].Value) {
|
if tokens[*index].Type == tokenizer.SYMBOL && slices.Contains([]string{"-", "~"}, tokens[*index].Value) {
|
||||||
op := tokens[*index].Value
|
op := tokens[*index].Value
|
||||||
@@ -66,11 +76,11 @@ func compileTerm(output *strings.Builder, tokens []tokenizer.Token, index *int)
|
|||||||
if tokens[*index].Value == "this" {
|
if tokens[*index].Value == "this" {
|
||||||
variable, found := table.GetVariable([]*map[string]table.Variable{&subroutineSymbolTable}, tokens[*index].Value)
|
variable, found := table.GetVariable([]*map[string]table.Variable{&subroutineSymbolTable}, tokens[*index].Value)
|
||||||
|
|
||||||
if !found {
|
if found {
|
||||||
return errors.New("Invalid identifier!")
|
|
||||||
}
|
|
||||||
|
|
||||||
code.WritePush(output, segmentFromVariableKind(variable.Kind), variable.Count)
|
code.WritePush(output, segmentFromVariableKind(variable.Kind), variable.Count)
|
||||||
|
} else {
|
||||||
|
code.WritePush(output, code.POINTER, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if tokens[*index].Value == "true" {
|
if tokens[*index].Value == "true" {
|
||||||
@@ -112,7 +122,7 @@ func compileTerm(output *strings.Builder, tokens []tokenizer.Token, index *int)
|
|||||||
|
|
||||||
var identifier string
|
var identifier string
|
||||||
|
|
||||||
if found {
|
if found && !slices.Contains([]string{"(", "."}, tokens[(*index)+1].Value) {
|
||||||
code.WritePush(output, segmentFromVariableKind(variable.Kind), variable.Count)
|
code.WritePush(output, segmentFromVariableKind(variable.Kind), variable.Count)
|
||||||
} else {
|
} else {
|
||||||
identifier = tokens[*index].Value
|
identifier = tokens[*index].Value
|
||||||
@@ -282,10 +292,19 @@ func compileVariableDeclaration(output *strings.Builder, tokens []tokenizer.Toke
|
|||||||
func compileSubroutineCall(output *strings.Builder, tokens []tokenizer.Token, index *int, identifier string) error {
|
func compileSubroutineCall(output *strings.Builder, tokens []tokenizer.Token, index *int, identifier string) error {
|
||||||
var class string
|
var class string
|
||||||
var function string
|
var function string
|
||||||
|
var subroutine string
|
||||||
|
|
||||||
if tokens[*index].Value == "." {
|
instanceCallingMethod := false
|
||||||
|
|
||||||
|
switch tokens[*index].Value {
|
||||||
|
case ".":
|
||||||
|
variable, found := table.GetVariable([]*map[string]table.Variable{&subroutineSymbolTable, &classSymbolTable}, identifier)
|
||||||
|
|
||||||
|
if found {
|
||||||
|
class = variable.Type
|
||||||
|
} else {
|
||||||
class = identifier
|
class = identifier
|
||||||
|
}
|
||||||
|
|
||||||
(*index)++
|
(*index)++
|
||||||
|
|
||||||
@@ -293,9 +312,23 @@ func compileSubroutineCall(output *strings.Builder, tokens []tokenizer.Token, in
|
|||||||
return errors.New("Invalid subroutine name!")
|
return errors.New("Invalid subroutine name!")
|
||||||
}
|
}
|
||||||
|
|
||||||
function = class + "." + tokens[*index].Value
|
subroutine = tokens[*index].Value
|
||||||
|
function = class + "." + subroutine
|
||||||
|
|
||||||
|
// This assumes that the called subroutine is a method for now.
|
||||||
|
if found {
|
||||||
|
code.WritePush(output, segmentFromVariableKind(variable.Kind), variable.Count)
|
||||||
|
instanceCallingMethod = true
|
||||||
|
}
|
||||||
|
|
||||||
(*index)++
|
(*index)++
|
||||||
|
case "(":
|
||||||
|
subroutine = identifier
|
||||||
|
function = className + "." + identifier
|
||||||
|
|
||||||
|
if isMethodName(tokens, subroutine) {
|
||||||
|
code.WritePush(output, code.POINTER, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if tokens[*index].Value != "(" {
|
if tokens[*index].Value != "(" {
|
||||||
@@ -314,6 +347,10 @@ func compileSubroutineCall(output *strings.Builder, tokens []tokenizer.Token, in
|
|||||||
return errors.New("Missing subroutine call closing parenthese!")
|
return errors.New("Missing subroutine call closing parenthese!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isMethodName(tokens, subroutine) || instanceCallingMethod {
|
||||||
|
args++
|
||||||
|
}
|
||||||
|
|
||||||
code.WriteCall(output, function, args)
|
code.WriteCall(output, function, args)
|
||||||
|
|
||||||
(*index)++
|
(*index)++
|
||||||
@@ -375,7 +412,6 @@ func compileLetStatement(output *strings.Builder, tokens []tokenizer.Token, inde
|
|||||||
}
|
}
|
||||||
|
|
||||||
func compileIfStatement(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
|
func compileIfStatement(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
|
||||||
endLabel := "IF_END_" + fmt.Sprint(ifLabelIndex)
|
|
||||||
elseLabel := "IF_ELSE_" + fmt.Sprint(ifLabelIndex)
|
elseLabel := "IF_ELSE_" + fmt.Sprint(ifLabelIndex)
|
||||||
|
|
||||||
ifLabelIndex++
|
ifLabelIndex++
|
||||||
@@ -415,14 +451,16 @@ func compileIfStatement(output *strings.Builder, tokens []tokenizer.Token, index
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
code.WriteGoto(output, endLabel)
|
|
||||||
|
|
||||||
if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != "}" {
|
if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != "}" {
|
||||||
return errors.New("Missing if statement closing curly brace!")
|
return errors.New("Missing if statement closing curly brace!")
|
||||||
}
|
}
|
||||||
|
|
||||||
(*index)++
|
(*index)++
|
||||||
|
|
||||||
|
if tokens[*index].Value != "else" {
|
||||||
|
code.WriteLabel(output, elseLabel)
|
||||||
|
}
|
||||||
|
|
||||||
if tokens[*index].Type == tokenizer.KEYWORD && tokens[*index].Value == "else" {
|
if tokens[*index].Type == tokenizer.KEYWORD && tokens[*index].Value == "else" {
|
||||||
(*index)++
|
(*index)++
|
||||||
|
|
||||||
@@ -445,14 +483,12 @@ func compileIfStatement(output *strings.Builder, tokens []tokenizer.Token, index
|
|||||||
(*index)++
|
(*index)++
|
||||||
}
|
}
|
||||||
|
|
||||||
code.WriteLabel(output, endLabel)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileWhileStatement(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
|
func compileWhileStatement(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
|
||||||
startLabel := "WHILE_START_"+fmt.Sprint(whileLabelIndex)
|
startLabel := "WHILE_START_" + fmt.Sprint(whileLabelIndex)
|
||||||
endLabel := "WHILE_END_"+fmt.Sprint(whileLabelIndex)
|
endLabel := "WHILE_END_" + fmt.Sprint(whileLabelIndex)
|
||||||
|
|
||||||
whileLabelIndex++
|
whileLabelIndex++
|
||||||
|
|
||||||
@@ -593,7 +629,7 @@ func compileStatements(output *strings.Builder, tokens []tokenizer.Token, index
|
|||||||
return compileStatements(output, tokens, index)
|
return compileStatements(output, tokens, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileSubroutineBody(output *strings.Builder, tokens []tokenizer.Token, index *int, function string, isMethod bool) error {
|
func compileSubroutineBody(output *strings.Builder, tokens []tokenizer.Token, index *int, function string, isMethod bool, isConstructor bool) error {
|
||||||
if tokens[*index].Type == tokenizer.KEYWORD && tokens[*index].Value == "var" {
|
if tokens[*index].Type == tokenizer.KEYWORD && tokens[*index].Value == "var" {
|
||||||
if err := compileVariableDeclaration(output, tokens, index); err != nil {
|
if err := compileVariableDeclaration(output, tokens, index); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -602,6 +638,12 @@ func compileSubroutineBody(output *strings.Builder, tokens []tokenizer.Token, in
|
|||||||
|
|
||||||
code.WriteFunction(output, className+"."+function, table.CountVariables(&subroutineSymbolTable, table.VAR)+1)
|
code.WriteFunction(output, className+"."+function, table.CountVariables(&subroutineSymbolTable, table.VAR)+1)
|
||||||
|
|
||||||
|
if isConstructor {
|
||||||
|
code.WritePush(output, code.CONSTANT, table.CountVariables(&classSymbolTable, table.FIELD)+1)
|
||||||
|
code.WriteCall(output, "Memory.alloc", 1)
|
||||||
|
code.WritePop(output, code.POINTER, 0)
|
||||||
|
}
|
||||||
|
|
||||||
if isMethod {
|
if isMethod {
|
||||||
code.WritePush(output, code.ARGUMENT, 0)
|
code.WritePush(output, code.ARGUMENT, 0)
|
||||||
code.WritePop(output, code.POINTER, 0)
|
code.WritePop(output, code.POINTER, 0)
|
||||||
@@ -622,6 +664,7 @@ func compileSubroutineDeclaration(output *strings.Builder, tokens []tokenizer.To
|
|||||||
}
|
}
|
||||||
|
|
||||||
isMethod := tokens[*index].Value == "method"
|
isMethod := tokens[*index].Value == "method"
|
||||||
|
isConstructor := tokens[*index].Value == "constructor"
|
||||||
|
|
||||||
(*index)++
|
(*index)++
|
||||||
|
|
||||||
@@ -668,7 +711,7 @@ func compileSubroutineDeclaration(output *strings.Builder, tokens []tokenizer.To
|
|||||||
|
|
||||||
(*index)++
|
(*index)++
|
||||||
|
|
||||||
if err := compileSubroutineBody(output, tokens, index, function, isMethod); err != nil {
|
if err := compileSubroutineBody(output, tokens, index, function, isMethod, isConstructor); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user