From 10adbffd5fbbd50a5690ac2ac25e94130aef0131 Mon Sep 17 00:00:00 2001 From: Hazem Krimi Date: Tue, 21 Apr 2026 16:36:29 +0100 Subject: [PATCH] fix: compilation engine errors --- .../compilation-engine/compilation-engine.go | 192 +++++++++++------- internal/tokenizer/tokenizer.go | 2 +- 2 files changed, 121 insertions(+), 73 deletions(-) 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{