diff --git a/Compiler/Compiler.csproj b/Compiler/Compiler.csproj index 18bda8a..45dcced 100644 --- a/Compiler/Compiler.csproj +++ b/Compiler/Compiler.csproj @@ -1,7 +1,7 @@  - Exe + WinExe net8.0-windows enable enable diff --git a/Compiler/Models/Parser/DeclareParser.cs b/Compiler/Models/Parser/DeclareParser.cs deleted file mode 100644 index c49d9be..0000000 --- a/Compiler/Models/Parser/DeclareParser.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Compiler; - -public class DeclareParser : IParser -{ - private List tokens; - private Lexeme CurrToken; - private int CurrIndex; - private int MaxIndex; - - public List Errors { get; set; } - - public DeclareParser() - { - Errors = new List(); - } - - public List Parse(List tokensList) - { - Errors.Clear(); - if (tokensList.Count <= 0) - return Errors; - tokens = tokensList; - CurrIndex = 0; - MaxIndex = tokensList.Count - 1; - CurrToken = tokens[CurrIndex]; - - - - return Errors; - } -} diff --git a/Compiler/Models/Parser/ReqParser.cs b/Compiler/Models/Parser/ReqParser.cs index efc12ac..5e67144 100644 --- a/Compiler/Models/Parser/ReqParser.cs +++ b/Compiler/Models/Parser/ReqParser.cs @@ -26,6 +26,7 @@ public List Parse(List tokensList) Errors.Clear(); if (tokensList.Count <= 0) return Errors; + GetAndRemoveInvalidLexemes(tokensList); tokens = tokensList; CurrIndex = 0; MaxIndex = tokensList.Count - 1; @@ -37,15 +38,24 @@ public List Parse(List tokensList) } catch (SyntaxErrorException) { - log("Syntax Error: Обнаружено незаконченное выражение."); + if (CurrToken.Type != LexemeType.Semicolon) + Errors.Add(new ParserError($"Выражение незакончено", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); } return Errors; } - private void log(string str) + public void GetAndRemoveInvalidLexemes(List lexemes) { - + for (int i = lexemes.Count - 1; i >= 0; i--) + { + var lexeme = lexemes[i]; + if (lexeme.Type == LexemeType.Whitespace || lexeme.Type == LexemeType.NewLine || lexeme.Type == LexemeType.InvalidCharacter) + { + Errors.Add(new ParserError($"Недопустимый символ \"{lexeme.Value}\"", lexeme.StartIndex, lexeme.EndIndex, ErrorType.UnfinishedExpression)); + lexemes.RemoveAt(i); + } + } } private void ChangeCurrentToken() @@ -54,12 +64,6 @@ private void ChangeCurrentToken() { CurrIndex++; CurrToken = tokens[CurrIndex]; - - if (CurrToken.Type == LexemeType.InvalidCharacter) - { - Errors.Add(new ParserError($"Встречен некорректный символ \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); - ChangeCurrentToken(); - } } else { @@ -78,14 +82,22 @@ private void Z(bool get, bool neutralize = false) { if (get) ChangeCurrentToken(); - if (CurrToken.Type == LexemeType.DECLARE || neutralize) + if (CurrToken.Type == LexemeType.DECLARE) { E(true); } else { - Errors.Add(new ParserError($"Ожидалось ключевое слово DECLARE, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); - E(true); + if (CurrToken.Type == LexemeType.Identifier && GetNextType() == LexemeType.CONSTANT) + { + Errors.Add(new ParserError($"Пропущено ключевое слово DECLARE", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + E(false); + } + else + { + Errors.Add(new ParserError($"Ожидалось ключевое слово DECLARE, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + E(true); + } } } @@ -93,14 +105,26 @@ private void E(bool get, bool neutralize = false) { if (get) ChangeCurrentToken(); - if (CurrToken.Type == LexemeType.Identifier || neutralize) + if (CurrToken.Type == LexemeType.Identifier) { CONST(true); } else { - Errors.Add(new ParserError($"Ожидался идентификатор, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); - CONST(true); + if (CurrToken.Type == LexemeType.CONSTANT) + { + Errors.Add(new ParserError($"Пропущен идентификатор", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + CONST(false); + } + else + { + Errors.Add(new ParserError($"Ожидался идентификатор, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + + if (GetNextType() == LexemeType.Identifier) + E(true); + else + CONST(true); + } } } @@ -108,14 +132,26 @@ private void CONST(bool get, bool neutralize = false) { if (get) ChangeCurrentToken(); - if (CurrToken.Type == LexemeType.CONSTANT || neutralize) + if (CurrToken.Type == LexemeType.CONSTANT) { INT(true); } else { - Errors.Add(new ParserError($"Ожидалось ключевое слово CONSTANT, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); - INT(true); + if (CurrToken.Type == LexemeType.INTEGER) + { + Errors.Add(new ParserError($"Пропущено ключевое слово CONSTANT", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + INT(false); + } + else + { + Errors.Add(new ParserError($"Ожидалось ключевое слово CONSTANT, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + + if (GetNextType() == LexemeType.CONSTANT) + CONST(true); + else + INT(true); + } } } @@ -123,14 +159,26 @@ private void INT(bool get, bool neutralize = false) { if (get) ChangeCurrentToken(); - if (CurrToken.Type == LexemeType.INTEGER || neutralize) + if (CurrToken.Type == LexemeType.INTEGER) { ASSIGN(true); } else { - Errors.Add(new ParserError($"Ожидалось ключевое слово INTEGER, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); - ASSIGN(true); + if (CurrToken.Type == LexemeType.AssignmentOperator) + { + Errors.Add(new ParserError($"Пропущено ключевое слово INTEGER", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + ASSIGN(false); + } + else + { + Errors.Add(new ParserError($"Ожидалось ключевое слово INTEGER, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + + if (GetNextType() == LexemeType.INTEGER) + INT(true); + else + ASSIGN(true); + } } } @@ -138,14 +186,26 @@ private void ASSIGN(bool get, bool neutralize = false) { if (get) ChangeCurrentToken(); - if (CurrToken.Type == LexemeType.AssignmentOperator || neutralize) + if (CurrToken.Type == LexemeType.AssignmentOperator) { NUMBER(true); } else { - Errors.Add(new ParserError($"Ожидался оператор присваивания, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); - NUMBER(true); + if (CurrToken.Type == LexemeType.Sign || CurrToken.Type == LexemeType.UnsignedInteger) + { + Errors.Add(new ParserError($"Пропущен оператор присваивания", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + NUMBER(false); + } + else + { + Errors.Add(new ParserError($"Ожидался оператор присваивания, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + + if (GetNextType() == LexemeType.AssignmentOperator) + ASSIGN(true); + else + NUMBER(true); + } } } @@ -159,8 +219,20 @@ private void NUMBER(bool get, bool neutralize = false) } else { - Errors.Add(new ParserError($"Ожидался знак или число, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); - UNSIGNEDINT(true); + if (CurrToken.Type == LexemeType.Semicolon) + { + Errors.Add(new ParserError($"Пропущен знак или число", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + UNSIGNEDINT(false); + } + else + { + Errors.Add(new ParserError($"Ожидался знак или число, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + + if (GetNextType() == LexemeType.Sign || GetNextType() == LexemeType.UnsignedInteger) + NUMBER(true); + else + UNSIGNEDINT(true, true); + } } } @@ -168,14 +240,27 @@ private void UNSIGNEDINT(bool get, bool neutralize = false) { if (get) ChangeCurrentToken(); - if (CurrToken.Type == LexemeType.UnsignedInteger || neutralize) + if (CurrToken.Type == LexemeType.UnsignedInteger) { END(true); } else { - Errors.Add(new ParserError($"Ожидалось число, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); - END(true); + if (CurrToken.Type == LexemeType.Semicolon) + { + if (!neutralize) + Errors.Add(new ParserError($"Пропущено число", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + END(false); + } + else + { + Errors.Add(new ParserError($"Ожидалось число, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + + if (GetNextType() == LexemeType.UnsignedInteger) + UNSIGNEDINT(true); + else + END(true); + } } } @@ -183,14 +268,27 @@ private void END(bool get, bool neutralize = false) { if (get) ChangeCurrentToken(); - if (CurrToken.Type == LexemeType.Semicolon || neutralize) + if (CurrToken.Type == LexemeType.Semicolon) { Z(true); } else { - Errors.Add(new ParserError($"Ожидался идентификатор, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); - Z(true); + if (CurrToken.Type == LexemeType.DECLARE || GetNextType() == LexemeType.Error) + { + Errors.Add(new ParserError($"Пропущен оператор конца выражения", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + if (GetNextType() != LexemeType.Error) + Z(false); + } + else + { + Errors.Add(new ParserError($"Ожидался оператор конца выражения, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); + + if (GetNextType() == LexemeType.Semicolon) + END(true); + else + Z(true); + } } } } \ No newline at end of file diff --git a/Compiler/Resources/About.html b/Compiler/Resources/About.html index 9780240..7f9424a 100644 --- a/Compiler/Resources/About.html +++ b/Compiler/Resources/About.html @@ -44,7 +44,7 @@

О программе

Логотип

Название программы: Компилятор

-

Версия программы: 4.2.2

+

Версия программы: 4.3.0b

Автор: Сагайдак А.Е., АВТ-113

Описание: текстовый редактор с функциями языкового процессора

2024 г.

diff --git a/Compiler/Resources/MethodOfAnalysis.html b/Compiler/Resources/MethodOfAnalysis.html index ccc67e8..7d9a421 100644 --- a/Compiler/Resources/MethodOfAnalysis.html +++ b/Compiler/Resources/MethodOfAnalysis.html @@ -4,146 +4,307 @@ Метод анализа + + +

Метод анализа

Методом анализа является метод рекурсивного спуска, представленный кодом ниже:

-

-private void Z(bool get, bool neutralize = false)
+

+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Compiler;
+
+public class ReqParser : IParser
 {
-    if (get) ChangeCurrentToken();
+    private List tokens;
+    private Lexeme CurrToken;
+    private int CurrIndex;
+    private int MaxIndex;
+
+    public List Errors { get; set; }
 
-    if (CurrToken.Type == LexemeType.DECLARE || neutralize)
+    public ReqParser()
     {
-        E(true);
+        Errors = new List();
     }
-    else
+
+    public List Parse(List tokensList)
     {
-        Errors.Add(new ParserError($"Ожидалось ключевое слово DECLARE,
-            а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex,
-            tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
-        E(true);
-    }
-}
+        Errors.Clear();
+        if (tokensList.Count <= 0)
+            return Errors;
+        GetAndRemoveInvalidLexemes(tokensList);
+        tokens = tokensList;
+        CurrIndex = 0;
+        MaxIndex = tokensList.Count - 1;
+        CurrToken = tokens[CurrIndex];
 
-private void E(bool get, bool neutralize = false)
-{
-    if (get) ChangeCurrentToken();
+        try
+        {
+            Z(false);
+        }
+        catch (SyntaxErrorException)
+        {
+            if (CurrToken.Type != LexemeType.Semicolon)
+                Errors.Add(new ParserError($"Выражение незакончено", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression)); 
+        }
 
-    if (CurrToken.Type == LexemeType.Identifier || neutralize)
-    {
-        CONST(true);
+        return Errors;
     }
-    else
+
+    public void GetAndRemoveInvalidLexemes(List lexemes)
     {
-        Errors.Add(new ParserError($"Ожидался идентификатор,
-            а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex,
-            tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
-        CONST(true);
+        for (int i = lexemes.Count - 1; i >= 0; i--)
+        {
+            var lexeme = lexemes[i];
+            if (lexeme.Type == LexemeType.Whitespace || lexeme.Type == LexemeType.NewLine || lexeme.Type == LexemeType.InvalidCharacter)
+            {
+                Errors.Add(new ParserError($"Недопустимый символ \"{lexeme.Value}\"", lexeme.StartIndex, lexeme.EndIndex, ErrorType.UnfinishedExpression));
+                lexemes.RemoveAt(i);
+            }
+        }
     }
-}
-
-private void CONST(bool get, bool neutralize = false)
-{
-    if (get) ChangeCurrentToken();
 
-    if (CurrToken.Type == LexemeType.CONSTANT || neutralize)
+    private void ChangeCurrentToken()
     {
-        INT(true);
+        if (CanGetNext())
+        {
+            CurrIndex++;
+            CurrToken = tokens[CurrIndex];
+        }
+        else
+        {
+            throw new SyntaxErrorException();
+        }
     }
-    else
+
+    private LexemeType GetNextType()
     {
-        Errors.Add(new ParserError($"Ожидалось ключевое слово CONSTANT,
-            а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex,
-            tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
-        INT(true);
+        return CanGetNext() ? tokens[CurrIndex + 1].Type : LexemeType.Error;
     }
-}
 
-private void INT(bool get, bool neutralize = false)
-{
-    if (get) ChangeCurrentToken();
+    private bool CanGetNext() => CurrIndex < MaxIndex;
 
-    if (CurrToken.Type == LexemeType.INTEGER || neutralize)
+    private void Z(bool get, bool neutralize = false)
     {
-        ASSIGN(true);
+        if (get) ChangeCurrentToken();
+
+        if (CurrToken.Type == LexemeType.DECLARE)
+        {
+            E(true);
+        }
+        else
+        {
+            if (CurrToken.Type == LexemeType.Identifier && GetNextType() == LexemeType.CONSTANT)
+            {
+                Errors.Add(new ParserError($"Пропущено ключевое слово DECLARE", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+                E(false);
+            }
+            else
+            {
+                Errors.Add(new ParserError($"Ожидалось ключевое слово DECLARE, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+                E(true);
+            }
+        }
     }
-    else
+
+    private void E(bool get, bool neutralize = false)
     {
-        Errors.Add(new ParserError($"Ожидалось ключевое слово INTEGER,
-            а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex,
-            tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
-        ASSIGN(true);
-    }
-}
+        if (get) ChangeCurrentToken();
 
-private void ASSIGN(bool get, bool neutralize = false)
-{
-    if (get) ChangeCurrentToken();
+        if (CurrToken.Type == LexemeType.Identifier)
+        {
+            CONST(true);
+        }
+        else
+        {
+            if (CurrToken.Type == LexemeType.CONSTANT)
+            {
+                Errors.Add(new ParserError($"Пропущен идентификатор", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+                CONST(false);
+            }
+            else
+            {
+                Errors.Add(new ParserError($"Ожидался идентификатор, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
 
-    if (CurrToken.Type == LexemeType.AssignmentOperator || neutralize)
-    {
-        NUMBER(true);
+                if (GetNextType() == LexemeType.Identifier)
+                    E(true);
+                else
+                    CONST(true);
+            }
+        }
     }
-    else
+
+    private void CONST(bool get, bool neutralize = false)
     {
-        Errors.Add(new ParserError($"Ожидался оператор присваивания,
-            а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex,
-            tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
-        NUMBER(true);
-    }
-}
+        if (get) ChangeCurrentToken();
 
-private void NUMBER(bool get, bool neutralize = false)
-{
-    if (get) ChangeCurrentToken();
+        if (CurrToken.Type == LexemeType.CONSTANT)
+        {
+            INT(true);
+        }
+        else
+        {
+            if (CurrToken.Type == LexemeType.INTEGER)
+            {
+                Errors.Add(new ParserError($"Пропущено ключевое слово CONSTANT", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+                INT(false);
+            }
+            else
+            {
+                Errors.Add(new ParserError($"Ожидалось ключевое слово CONSTANT, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
 
-    if (CurrToken.Type == LexemeType.Sign || CurrToken.Type == LexemeType.UnsignedInteger
-            || neutralize)
-    {
-        UNSIGNEDINT(CurrToken.Type == LexemeType.Sign);
+                if (GetNextType() == LexemeType.CONSTANT)
+                    CONST(true);
+                else
+                    INT(true);
+            }
+        }
     }
-    else
+
+    private void INT(bool get, bool neutralize = false)
     {
-        Errors.Add(new ParserError($"Ожидался знак или число,
-            а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex,
-            tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
-        UNSIGNEDINT(true);
-    }
-}
+        if (get) ChangeCurrentToken();
 
-private void UNSIGNEDINT(bool get, bool neutralize = false)
-{
-    if (get) ChangeCurrentToken();
+        if (CurrToken.Type == LexemeType.INTEGER)
+        {
+            ASSIGN(true);
+        }
+        else
+        {
+            if (CurrToken.Type == LexemeType.AssignmentOperator)
+            {
+                Errors.Add(new ParserError($"Пропущено ключевое слово INTEGER", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+                ASSIGN(false);
+            }
+            else
+            {
+                Errors.Add(new ParserError($"Ожидалось ключевое слово INTEGER, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+                
+                if (GetNextType() == LexemeType.INTEGER)
+                    INT(true);
+                else
+                    ASSIGN(true);
+            }
+        }
+    }
 
-    if (CurrToken.Type == LexemeType.UnsignedInteger || neutralize)
+    private void ASSIGN(bool get, bool neutralize = false)
     {
-        END(true);
+        if (get) ChangeCurrentToken();
+
+        if (CurrToken.Type == LexemeType.AssignmentOperator)
+        {
+            NUMBER(true);
+        }
+        else
+        {
+            if (CurrToken.Type == LexemeType.Sign || CurrToken.Type == LexemeType.UnsignedInteger)
+            {
+                Errors.Add(new ParserError($"Пропущен оператор присваивания", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+                NUMBER(false);
+            }
+            else
+            {
+                Errors.Add(new ParserError($"Ожидался оператор присваивания, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+
+                if (GetNextType() == LexemeType.AssignmentOperator)
+                    ASSIGN(true);
+                else
+                    NUMBER(true);
+            }
+        }
     }
-    else
+
+    private void NUMBER(bool get, bool neutralize = false)
     {
-        Errors.Add(new ParserError($"Ожидалось число,
-            а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex,
-            tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
-        END(true);
-    }
-}
+        if (get) ChangeCurrentToken();
 
-private void END(bool get, bool neutralize = false)
-{
-    if (get) ChangeCurrentToken();
+        if (CurrToken.Type == LexemeType.Sign || CurrToken.Type == LexemeType.UnsignedInteger || neutralize)
+        {
+            UNSIGNEDINT(CurrToken.Type == LexemeType.Sign);
+        }
+        else
+        {
+            if (CurrToken.Type == LexemeType.Semicolon)
+            {
+                Errors.Add(new ParserError($"Пропущен знак или число", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+                UNSIGNEDINT(false);
+            }
+            else
+            {
+                Errors.Add(new ParserError($"Ожидался знак или число, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+
+                if (GetNextType() == LexemeType.Sign || GetNextType() == LexemeType.UnsignedInteger)
+                    NUMBER(true);
+                else
+                    UNSIGNEDINT(true, true);
+            }
+        }
+    }
 
-    if (CurrToken.Type == LexemeType.Semicolon || neutralize)
+    private void UNSIGNEDINT(bool get, bool neutralize = false)
     {
-        Z(true);
+        if (get) ChangeCurrentToken();
+
+        if (CurrToken.Type == LexemeType.UnsignedInteger)
+        {
+            END(true);
+        }
+        else
+        {
+            if (CurrToken.Type == LexemeType.Semicolon)
+            {
+                if (!neutralize)
+                    Errors.Add(new ParserError($"Пропущено число", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+                END(false);
+            }
+            else
+            {
+                Errors.Add(new ParserError($"Ожидалось число, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+
+                if (GetNextType() == LexemeType.UnsignedInteger)
+                    UNSIGNEDINT(true);
+                else
+                    END(true);
+            }
+        }
     }
-    else
+
+    private void END(bool get, bool neutralize = false)
     {
-        Errors.Add(new ParserError($"Ожидался идентификатор,
-            а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex,
-            tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
-        Z(true);
+        if (get) ChangeCurrentToken();
+
+        if (CurrToken.Type == LexemeType.Semicolon)
+        {
+            Z(true);
+        }
+        else
+        {
+            if (CurrToken.Type == LexemeType.DECLARE || GetNextType() == LexemeType.Error)
+            {
+                Errors.Add(new ParserError($"Пропущен оператор конца выражения", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+                if (GetNextType() != LexemeType.Error)
+                    Z(false);
+            }
+            else
+            {
+                Errors.Add(new ParserError($"Ожидался оператор конца выражения, а встречено \"{CurrToken.Value}\"", CurrToken.StartIndex, tokens[MaxIndex].EndIndex, ErrorType.UnfinishedExpression));
+
+                if (GetNextType() == LexemeType.Semicolon)
+                    END(true);
+                else
+                    Z(true);
+            }
+        }
     }
 }
 
diff --git a/Compiler/Resources/correct_test_case.txt b/Compiler/Resources/correct_test_case.txt index 5a58a56..450daa7 100644 --- a/Compiler/Resources/correct_test_case.txt +++ b/Compiler/Resources/correct_test_case.txt @@ -1,6 +1 @@ -DECLARE product_price CONSTANT INTEGER = +150; -DECLARE expense_1_amount CONSTANT INTEGER = +50; -DECLARE product_price CONSTANT INTEGER = -150; - -DECLARE total_2 CONSTANT INTEGER = 50; DECLARE productPrice3 CONSTANT INTEGER = +150; - +DECLARE product_price CONSTANT INTEGER = +150; \ No newline at end of file diff --git a/Compiler/Resources/wrong_test_case.txt b/Compiler/Resources/wrong_test_case.txt index c228506..7cc11b9 100644 --- a/Compiler/Resources/wrong_test_case.txt +++ b/Compiler/Resources/wrong_test_case.txt @@ -1,2 +1 @@ -DECLAR "product_price CONSTANT INTEGER =@ +150; -DECLARE expense_1_amount INTEGER = +50; +DECLAR product_price CONSTANT =@ +150k; \ No newline at end of file diff --git a/README.md b/README.md index 5b11f41..019726f 100644 --- a/README.md +++ b/README.md @@ -196,9 +196,12 @@ P = { Согласно классификации Хомского, грамматика G[Z] является полностью автоматной. -### Граф конечного автомата +### Метод анализа + +В качестве метода анализа был выбран рекурсивный спуск. + +Метод рекурсивного спуска. Основная идея этого метода состоит в том, что каждому нетерминалу грамматики ставится в соответствие определенная программная единица, процедура или функция (например, в языке С функция), которая распознает цепочку, порождаемую этим нетерминалом. Такие процедуры (функции) вызываются в соответствии с правилами грамматики, причем иногда вызывают сами себя рекурсивно. Следовательно, языком реализации этого метода может быть лишь такой язык, который допускает рекурсию. -![Граф конечного автомата](/README_images/finite_state_machine.jpg) ### Тестовые примеры @@ -208,15 +211,11 @@ P = { 2. **Тест №2.** Пример ошибок. > - При нажатии на строку в таблице, соответствующий фрагмент текста подсвечивается в поле редактирования. - > - > - Нажатие кнопки справа от количества ошибок позволяет их автоматически исправить. ![Тест 2](/README_images/parser_test_2.png) 3. **Тест №3.** Пример ошибок. > - При нажатии на строку в таблице, соответствующий фрагмент текста подсвечивается в поле редактирования. - > - > - Нажатие кнопки справа от количества ошибок позволяет их автоматически исправить. ![Тест 3](/README_images/parser_test_1.png) @@ -228,8 +227,7 @@ P = { ### Метод Айронса -Разрабатываемый синтаксический анализатор построен на базе автоматной грамматики. При нахождении лексемы, которая не соответствует грамматике предлагается свести алгоритм нейтрализации к последовательному -удалению следующего символа во входной цепочке до тех пор, пока следующий символ не окажется одним из допустимых в данный момент разбора. +Разрабатываемый синтаксический анализатор построен на базе автоматной грамматики. При нахождении лексемы, которая не соответствует грамматике предлагается свести алгоритм нейтрализации к последовательному удалению следующего символа во входной цепочке до тех пор, пока следующий символ не окажется одним из допустимых в данный момент разбора. Этот алгоритм был мной уже реализован в Лабораторной работе №3. В таблице ошибок выводятся их местоположение и текст ошибки, содержащий информацию об отброшенном фрагменте. @@ -238,14 +236,10 @@ P = { 1. **Тест №1.** Пример ошибок. > - При нажатии на строку в таблице, соответствующий фрагмент текста подсвечивается в поле редактирования. - > - > - Нажатие кнопки справа от количества ошибок позволяет их автоматически исправить. ![Тест 2](/README_images/parser_test_2.png) 2. **Тест №2.** Пример ошибок. > - При нажатии на строку в таблице, соответствующий фрагмент текста подсвечивается в поле редактирования. - > - > - Нажатие кнопки справа от количества ошибок позволяет их автоматически исправить. ![Тест 3](/README_images/parser_test_1.png) \ No newline at end of file diff --git a/README_images/about_click.png b/README_images/about_click.png index b2885b3..51f5986 100644 Binary files a/README_images/about_click.png and b/README_images/about_click.png differ diff --git a/README_images/finite_state_machine.jpg b/README_images/finite_state_machine.jpg deleted file mode 100644 index 89021bb..0000000 Binary files a/README_images/finite_state_machine.jpg and /dev/null differ diff --git a/README_images/parser_test_1.png b/README_images/parser_test_1.png index 4a9e2bc..1ba8748 100644 Binary files a/README_images/parser_test_1.png and b/README_images/parser_test_1.png differ diff --git a/README_images/parser_test_2.png b/README_images/parser_test_2.png index 1efbf5d..cd63f84 100644 Binary files a/README_images/parser_test_2.png and b/README_images/parser_test_2.png differ diff --git a/README_images/recursion_test_1.png b/README_images/recursion_test_1.png deleted file mode 100644 index e9e08fc..0000000 Binary files a/README_images/recursion_test_1.png and /dev/null differ