diff --git a/internal/compilation-engine/compilation-engine.go b/internal/compilation-engine/compilation-engine.go
index 0692355..11bce2d 100644
--- a/internal/compilation-engine/compilation-engine.go
+++ b/internal/compilation-engine/compilation-engine.go
@@ -16,7 +16,7 @@ func compileClassVarDec(output *strings.Builder, tokens []tokenizer.Token, index
output.WriteString(" " + tokens[*index].Value + " \n")
*(index)++
- if !slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER}, tokens[*index].Type) || !slices.Contains([]string{"int", "char", "boolean"}, tokens[*index].Value) {
+ if !slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER}, tokens[*index].Type) && !slices.Contains([]string{"int", "char", "boolean"}, tokens[*index].Value) {
return errors.New("Invalid variable type name!")
}
@@ -36,7 +36,7 @@ func compileClassVarDec(output *strings.Builder, tokens []tokenizer.Token, index
*(index)++
for tokens[*index].Type == tokenizer.SYMBOL && tokens[*index].Value == "," {
- output.WriteString(" " + tokens[*index].Value + " \n")
+ output.WriteString(" " + tokens[*index].Value + " \n")
(*index)++
if tokens[*index].Type != tokenizer.IDENTIFIER {
@@ -78,6 +78,9 @@ func compileParameterList(output *strings.Builder, tokens []tokenizer.Token, ind
*(index)++
if tokens[*index].Type == tokenizer.SYMBOL && tokens[*index].Value == "," {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
return compileParameterList(output, tokens, index)
}
@@ -92,7 +95,7 @@ func compileVariableDeclaration(output *strings.Builder, tokens []tokenizer.Toke
output.WriteString(" " + tokens[*index].Value + " \n")
*(index)++
- if !slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER}, tokens[*index].Type) || !slices.Contains([]string{"int", "char", "boolean"}, tokens[*index].Value) {
+ if !slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER}, tokens[*index].Type) && !slices.Contains([]string{"int", "char", "boolean"}, tokens[*index].Value) {
return errors.New("Invalid variable type name!")
}
@@ -133,6 +136,64 @@ func compileVariableDeclaration(output *strings.Builder, tokens []tokenizer.Toke
return compileVariableDeclaration(output, tokens, index)
}
+func compileExpression(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ if !slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER, tokenizer.INT_CONST, tokenizer.STR_CONST}, tokens[*index].Type) && !slices.Contains([]string{"true", "false", "null", "this"}, tokens[*index].Value) {
+ return errors.New("Invalid expression!")
+ }
+
+ output.WriteString("\n")
+ output.WriteString("\n")
+
+ switch tokens[*index].Type {
+ // case tokenizer.SYMBOL:
+ // var value string
+ //
+ // switch tokens[*index].Value {
+ // case "<":
+ // value = "<"
+ // case ">":
+ // value = ">"
+ // case "&":
+ // value = "&"
+ // default:
+ // value = tokens[*index].Value
+ // }
+ //
+ // output.WriteString(" " + value + " \n")
+ case tokenizer.KEYWORD:
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ case tokenizer.IDENTIFIER:
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ case tokenizer.INT_CONST:
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ case tokenizer.STR_CONST:
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ }
+
+ output.WriteString("\n")
+ output.WriteString("\n")
+ *(index)++
+
+ return nil
+}
+
+func compileExpressionList(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ if slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER, tokenizer.INT_CONST, tokenizer.STR_CONST}, tokens[*index].Type) || slices.Contains([]string{"true", "false", "null", "this"}, tokens[*index].Value) {
+ if err := compileExpression(output, tokens, index); err != nil {
+ return err
+ }
+
+ if tokens[*index].Type == tokenizer.SYMBOL && tokens[*index].Value == "," {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ (*index)++
+
+ return compileExpressionList(output, tokens, index)
+ }
+ }
+
+ return nil
+}
+
func compileLetStatement(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
if tokens[*index].Type != tokenizer.KEYWORD || tokens[*index].Value != "let" {
return errors.New("Invalid let statement!")
@@ -159,14 +220,10 @@ func compileLetStatement(output *strings.Builder, tokens []tokenizer.Token, inde
output.WriteString(" " + tokens[*index].Value + " \n")
(*index)++
- // TODO: Change to expression compilation
- if tokens[*index].Type != tokenizer.IDENTIFIER {
- return errors.New("Invalid variable name!")
+ if err := compileExpression(output, tokens, index); err != nil {
+ return err
}
- output.WriteString(" " + tokens[*index].Value + " \n")
- *(index)++
-
if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ";" {
return errors.New("Missing semicolon!")
}
@@ -192,18 +249,10 @@ func compileIfStatement(output *strings.Builder, tokens []tokenizer.Token, index
output.WriteString(" " + tokens[*index].Value + " \n")
*(index)++
- // TODO: Change to expression compilation
- if tokens[*index].Type != tokenizer.IDENTIFIER {
- return errors.New("Invalid variable name!")
+ if err := compileExpression(output, tokens, index); err != nil {
+ return err
}
- output.WriteString("\n")
- output.WriteString("\n")
- output.WriteString(" " + tokens[*index].Value + " \n")
- output.WriteString("\n")
- output.WriteString("\n")
- *(index)++
-
if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ")" {
return errors.New("Missing if statement closing parenthese!")
}
@@ -229,7 +278,7 @@ func compileIfStatement(output *strings.Builder, tokens []tokenizer.Token, index
output.WriteString(" " + tokens[*index].Value + " \n")
*(index)++
- if tokens[*index].Type == tokenizer.KEYWORD || tokens[*index].Value == "else" {
+ if tokens[*index].Type == tokenizer.KEYWORD && tokens[*index].Value == "else" {
output.WriteString(" " + tokens[*index].Value + " \n")
*(index)++
@@ -270,18 +319,10 @@ func compileWhileStatement(output *strings.Builder, tokens []tokenizer.Token, in
output.WriteString(" " + tokens[*index].Value + " \n")
*(index)++
- // TODO: Change to expression compilation
- if tokens[*index].Type != tokenizer.IDENTIFIER {
- return errors.New("Invalid variable name!")
+ if err := compileExpression(output, tokens, index); err != nil {
+ return err
}
- output.WriteString("\n")
- output.WriteString("\n")
- output.WriteString(" " + tokens[*index].Value + " \n")
- output.WriteString("\n")
- output.WriteString("\n")
- *(index)++
-
if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ")" {
return errors.New("Missing while statement closing parenthese!")
}
@@ -318,6 +359,49 @@ func compileDoStatement(output *strings.Builder, tokens []tokenizer.Token, index
output.WriteString(" " + tokens[*index].Value + " \n")
*(index)++
+ if tokens[*index].Type != tokenizer.IDENTIFIER {
+ return errors.New("Invalid variable name!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if tokens[*index].Type == tokenizer.SYMBOL && tokens[*index].Value == "." {
+ *(index)++
+
+ if tokens[*index].Type != tokenizer.IDENTIFIER {
+ return errors.New("Invalid variable name!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+ }
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != "(" {
+ return errors.New("Missing subroutine call opening parenthese!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if err := compileExpressionList(output, tokens, index); err != nil {
+ return err
+ }
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ")" {
+ return errors.New("Missing subroutine call closing parenthese!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ";" {
+ return errors.New("Missing semicolon!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ (*index)++
+
return nil
}
@@ -329,14 +413,10 @@ func compileReturnStatement(output *strings.Builder, tokens []tokenizer.Token, i
output.WriteString(" " + tokens[*index].Value + " \n")
*(index)++
- // TODO: Change to expression compilation
- if tokens[*index].Type == tokenizer.IDENTIFIER {
- output.WriteString("\n")
- output.WriteString("\n")
- output.WriteString(" " + tokens[*index].Value + " \n")
- output.WriteString("\n")
- output.WriteString("\n")
- *(index)++
+ if slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER, tokenizer.INT_CONST, tokenizer.STR_CONST}, tokens[*index].Type) {
+ if err := compileExpression(output, tokens, index); err != nil {
+ return err
+ }
}
if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ";" {
@@ -351,7 +431,7 @@ func compileReturnStatement(output *strings.Builder, tokens []tokenizer.Token, i
func compileStatements(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
if tokens[*index].Type != tokenizer.KEYWORD {
- return errors.New("Invalid statement!")
+ return nil
}
output.WriteString("<")
@@ -418,7 +498,7 @@ func compileSubroutineDeclaration(output *strings.Builder, tokens []tokenizer.To
output.WriteString(" " + tokens[*index].Value + " \n")
*(index)++
- if !slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER}, tokens[*index].Type) || !slices.Contains([]string{"void", "int", "char", "boolean"}, tokens[*index].Value) {
+ if !slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER}, tokens[*index].Type) && !slices.Contains([]string{"void", "int", "char", "boolean"}, tokens[*index].Value) {
return errors.New("Invalid subroutine return type!")
}
@@ -542,37 +622,5 @@ func ParseTokens(tokens []tokenizer.Token) (string, error) {
return "", err
}
- // output.WriteString("\n")
-
- // for _, token := range tokens {
- // switch token.Type {
- // case tokenizer.SYMBOL:
- // var value string
- //
- // switch token.Value {
- // case "<":
- // value = "<"
- // case ">":
- // value = ">"
- // case "&":
- // value = "&"
- // default:
- // value = token.Value
- // }
- //
- // output.WriteString(" " + value + " \n")
- // case tokenizer.KEYWORD:
- // output.WriteString(" " + token.Value + " \n")
- // case tokenizer.IDENTIFIER:
- // output.WriteString(" " + token.Value + " \n")
- // case tokenizer.INT_CONST:
- // output.WriteString(" " + token.Value + " \n")
- // case tokenizer.STR_CONST:
- // output.WriteString(" " + token.Value + " \n")
- // }
- // }
-
- // output.WriteString("\n")
-
return output.String(), nil
}
diff --git a/internal/tokenizer/tokenizer.go b/internal/tokenizer/tokenizer.go
index c08e8dd..d6f2961 100644
--- a/internal/tokenizer/tokenizer.go
+++ b/internal/tokenizer/tokenizer.go
@@ -14,9 +14,9 @@ type TokenType int
const (
KEYWORD TokenType = iota
SYMBOL
+ IDENTIFIER
INT_CONST
STR_CONST
- IDENTIFIER
)
var KEYWORDS = []string{