From d84f370daed8cf885f0d09372e0be4f801883796 Mon Sep 17 00:00:00 2001 From: Hazem Krimi Date: Wed, 22 Apr 2026 16:14:08 +0100 Subject: [PATCH] feat: finish syntax analyzer --- .../compilation-engine/compilation-engine.go | 163 ++++++++++++++---- 1 file changed, 128 insertions(+), 35 deletions(-) diff --git a/internal/compilation-engine/compilation-engine.go b/internal/compilation-engine/compilation-engine.go index 64c289d..58dbf9b 100644 --- a/internal/compilation-engine/compilation-engine.go +++ b/internal/compilation-engine/compilation-engine.go @@ -121,22 +121,128 @@ 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!") +func compileSubroutineCall(output *strings.Builder, tokens []tokenizer.Token, index *int) error { + + if tokens[*index].Value == "." { + WriteToken(output, tokens[*index], index) + + if tokens[*index].Type != tokenizer.IDENTIFIER { + return errors.New("Invalid subroutine name!") + } + + WriteToken(output, tokens[*index], index) + } + + if tokens[*index].Value != "(" { + return errors.New("Missing subroutine call opening parenthese!") } - output.WriteString("\n") - output.WriteString("\n") WriteToken(output, tokens[*index], index) - output.WriteString("\n") + + output.WriteString("\n") + + if err := compileExpressionList(output, tokens, index); err != nil { + return err + } + + output.WriteString("\n") + + if tokens[*index].Value != ")" { + return errors.New("Missing subroutine call closing parenthese!") + } + + WriteToken(output, tokens[*index], index) + + return nil +} + +func compileTerm(output *strings.Builder, tokens []tokenizer.Token, index *int) error { + output.WriteString("\n") + + if tokens[*index].Type == tokenizer.SYMBOL && slices.Contains([]string{"-", "~"}, tokens[*index].Value) { + WriteToken(output, tokens[*index], index) + + if err := compileTerm(output, tokens, index); err != nil { + return err + } + + output.WriteString("\n") + return nil + } + + if slices.Contains([]tokenizer.TokenType{tokenizer.INT_CONST, tokenizer.STR_CONST}, tokens[*index].Type) || slices.Contains([]string{"true", "false", "null", "this"}, tokens[*index].Value) { + WriteToken(output, tokens[*index], index) + output.WriteString("\n") + + return nil + } + + if tokens[*index].Type == tokenizer.SYMBOL && tokens[*index].Value == "(" { + WriteToken(output, tokens[*index], index) + + if err := compileExpression(output, tokens, index); err != nil { + return err + } + + if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ")" { + return errors.New("Invalid term!") + } + + WriteToken(output, tokens[*index], index) + output.WriteString("\n") + + return nil + } + + if tokens[*index].Type == tokenizer.IDENTIFIER { + WriteToken(output, tokens[*index], index) + + if tokens[*index].Value == "[" { + WriteToken(output, tokens[*index], index) + + if err := compileExpression(output, tokens, index); err != nil { + return err + } + + if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != "]" { + return errors.New("Invalid term!") + } + + WriteToken(output, tokens[*index], index) + } else if slices.Contains([]string{"(", "."}, tokens[*index].Value) { + if err := compileSubroutineCall(output, tokens, index); err != nil { + return err + } + } + + output.WriteString("\n") + } + + return nil +} + +func compileExpression(output *strings.Builder, tokens []tokenizer.Token, index *int) error { + output.WriteString("\n") + + if err := compileTerm(output, tokens, index); err != nil { + return err + } + + if slices.Contains([]string{"+", "-", "*", "/", "&", "|", "<", ">", "="}, tokens[*index].Value) { + WriteToken(output, tokens[*index], index) + + if err := compileTerm(output, tokens, index); err != nil { + return err + } + } + output.WriteString("\n") 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 slices.Contains([]tokenizer.TokenType{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 } @@ -166,6 +272,20 @@ func compileLetStatement(output *strings.Builder, tokens []tokenizer.Token, inde WriteToken(output, tokens[*index], index) + if tokens[*index].Value == "[" { + WriteToken(output, tokens[*index], index) + + if err := compileExpression(output, tokens, index); err != nil { + return err + } + + if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != "]" { + return errors.New("Invalid expression!") + } + + WriteToken(output, tokens[*index], index) + } + if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != "=" { return errors.New("Missing assignment!") } @@ -324,36 +444,10 @@ func compileDoStatement(output *strings.Builder, tokens []tokenizer.Token, index WriteToken(output, tokens[*index], index) - if tokens[*index].Type == tokenizer.SYMBOL && tokens[*index].Value == "." { - WriteToken(output, tokens[*index], index) - - if tokens[*index].Type != tokenizer.IDENTIFIER { - return errors.New("Invalid variable name!") - } - - WriteToken(output, tokens[*index], index) - } - - if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != "(" { - return errors.New("Missing subroutine call opening parenthese!") - } - - WriteToken(output, tokens[*index], index) - - output.WriteString("\n") - - if err := compileExpressionList(output, tokens, index); err != nil { + if err := compileSubroutineCall(output, tokens, index); err != nil { return err } - output.WriteString("\n") - - if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ")" { - return errors.New("Missing subroutine call closing parenthese!") - } - - WriteToken(output, tokens[*index], index) - if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ";" { return errors.New("Missing semicolon!") } @@ -478,7 +572,6 @@ func compileSubroutineDeclaration(output *strings.Builder, tokens []tokenizer.To return errors.New("Missing subroutine closing parenthese!") } - WriteToken(output, tokens[*index], index) output.WriteString("\n")