Beispiel #1
0
 /// <summary>
 /// Создать новый экземпляр парсера осуществляющего LL(1) разбор по таблице разбора.
 /// </summary>
 /// <param name="data">Строка принадлежность к граматике которой, необходимо определить.</param>
 /// <param name="startedRule">Стартовое правило грамматики.</param>
 internal Parser(string data, GrammarElement startedElement, Table table)
 {
     this.data  = data;
     this.table = table;
     stack      = new Stack <GrammarElement>();
     stack.Push(startedElement);
 }
Beispiel #2
0
        /// <summary>
        /// Развернуть элемент грамматики по направлющим символам.
        /// </summary>
        /// <param name="startingRule">Элемент грамматики, подлежащий развертыванию.</param>
        /// <param name="guideChars">Направляющие символы.</param>
        internal GrammarRulePart Unfold(GrammarElement startingRule, string guideChars)
        {
            if (!table.ContainsKey(startingRule))
            {
                throw new Exception("Строка не пренадлежит грамматике.");
            }

            GrammarRulePart result = null;

            foreach (var key in table[startingRule].Keys)
            {
                if (key == "" && result == null)
                {
                    result = table[startingRule][key];
                }
                else if (key.Length <= guideChars.Length && key == guideChars.Substring(0, key.Length))
                {
                    result = table[startingRule][key];
                    break;
                }
            }

            if (result == null)
            {
                throw new Exception("Строка не пренадлежит грамматике.");
            }

            return(result);
        }
Beispiel #3
0
 /// <summary>
 /// Дополняет сообщение об ошибке данными о номере строки и символа, в котором возникла ошибка. Также состоянием стека
 /// и оставшейся строкой разбора.
 /// </summary>
 /// <param name="mainMsg">Описание причины возникновения ошибки.</param>
 /// <param name="element">Елемент, на котором закончился разбор.</param>
 /// <param name="compareData">Оставшаяся, неразобранная строка.</param>
 private string GetExceptionMsg(string mainMsg, GrammarElement element, string compareData)
 {
     return($"{mainMsg + Environment.NewLine + Environment.NewLine}Исключение возникло при считывании символа или лексемы в " +
            $"строке №:{lineCounter}, символ №:{charCounter}.{Environment.NewLine + Environment.NewLine}Оставшаяся строка: " +
            $"{Environment.NewLine + compareData + Environment.NewLine + Environment.NewLine}Считан элемент со стека: " +
            $"{element + Environment.NewLine}Осталось на стеке: {string.Join(Environment.NewLine, stack.ToList())}");
 }
Beispiel #4
0
 /// <summary>
 /// Открывает нетерминал, проверяя возможные символьные совпадения, использую таблицу разбора.
 /// </summary>
 private void UnpackNonTerminal(GrammarElement element, string compareData)
 {
     try
     {
         ToStack(table.Unfold(element, compareData).Elements);
     }
     catch (Exception ex)
     {
         throw new Exception(GetExceptionMsg(ex.Message, element, compareData.ToString()));
     }
 }
Beispiel #5
0
 /// <summary>
 /// Вызов прикрепленных к элементу грамматики действий.
 /// </summary>
 /// <param name="element">Элемент.</param>
 /// <param name="compareData">Оставшаяся строка.</param>
 /// <param name="parameters">Параметры действия.</param>
 private void ExecuteActions(GrammarElement element, string compareData, object parameters)
 {
     try
     {
         element.Actions.ForEach(a => a.Invoke(parameters));
     }
     catch (Exception ex)
     {
         throw new Exception(GetExceptionMsg(ex.Message, element, compareData.ToString()));
     }
 }
Beispiel #6
0
 /// <summary>
 /// Рекурсивный метод, находящий коллекцию нетерминалов грамматики. Все найденные результаты добавляются в коллекцию nonterminals.
 /// </summary>
 /// <param name="element">Текущий рассматриваемый элемент.</param>
 /// <param name="nonterminals">Коллекция нетерминалов.</param>
 private void FindNonterminal(GrammarElement element, List <GrammarElement> nonterminals)
 {
     foreach (var rulePart in element.Rule.Right)
     {
         foreach (var elem in rulePart.Elements)
         {
             if (elem.Type == ElementType.NonTerminal && !nonterminals.Contains(elem))
             {
                 nonterminals.Add(elem);
                 FindNonterminal(elem, nonterminals);
             }
         }
     }
 }
Beispiel #7
0
        /// <summary>
        /// Создать новый экземпляр грамматики.
        /// </summary>
        /// <param name="grammar">Строка с описанием грамматики.</param>
        /// <param name="specialSymbols">Специальные символы грамматики.</param>
        public Grammar(string grammar, SpecialSymbols specialSymbols, ActionsContainer actions)
        {
            this.specialSymbols = specialSymbols;

            foreach (var line in grammar.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
            {
                Rules.Add(new GrammarRule(line, this.specialSymbols));
            }

            foreach (var rule in Rules)
            {
                rule.BuildRightPart(Rules, actions);
            }

            StartedElement = new GrammarElement(Rules.FirstOrDefault());
        }
Beispiel #8
0
        /// <summary>
        /// Проверка следующего элемента на стеке. Если элемент терминал, то выполняется проверка на символьное
        /// совпадение с входной строкой. Если элемент нетерминал, то выполняется распаковка (открытие) элемента.
        /// </summary>
        private void NextElementCheck(GrammarElement element, StringBuilder compareData)
        {
            switch (element.Type)
            {
            case ElementType.NonTerminal:
                ExecuteActions(element, compareData.ToString(), null);
                UnpackNonTerminal(element, compareData.ToString());
                break;

            case ElementType.Terminal:
                if (element.Characters.Length <= compareData.Length && element.Characters == compareData.ToString().Substring(0, element.Characters.Length))
                {
                    var data = compareData.ToString().Substring(0, element.Characters.Length);
                    RefreshCounters(data);
                    ExecuteActions(element, compareData.ToString(), data);
                    compareData.Remove(0, element.Characters.Length);
                }
                else
                {
                    throw new Exception(GetExceptionMsg("Данная строка не принадлежит граматике.", element, compareData.ToString()));
                }
                break;

            case ElementType.Range:
                if (compareData.Length > 0 && element.Characters.Contains(compareData.ToString().Substring(0, 1)))
                {
                    var data = compareData.ToString().Substring(0, 1);
                    RefreshCounters(data);
                    ExecuteActions(element, compareData.ToString(), data);
                    compareData.Remove(0, 1);
                }
                else
                {
                    throw new Exception(GetExceptionMsg("Данная строка не принадлежит граматике.", element, compareData.ToString()));
                }
                break;

            case ElementType.Empty:
                ExecuteActions(element, compareData.ToString(), null);
                break;

            default:
                throw new Exception("Неизвестный тип элемента.");
            }
        }
Beispiel #9
0
        /// <summary>
        /// Найти все варианты раскрытия переданного параметром нетерминала. Результат возвращается в
        /// виде словаря где TKey - направляющие символы, TValue - часть правила грамматики в которою
        /// раскроется нетерминал по направляющим символам TKey.
        /// </summary>
        private Dictionary <string, GrammarRulePart> FindUnfoldedWays(GrammarElement nonterm)
        {
            Dictionary <string, GrammarRulePart> result = new Dictionary <string, GrammarRulePart>();

            foreach (var rulePart in nonterm.Rule.Right)
            {
                List <string> guideChars = new List <string>();
                GetGuideChars(rulePart.Elements.First(), guideChars);

                foreach (var str in guideChars)
                {
                    if (result.ContainsKey(str))
                    {
                        throw new Exception("Ne LL1");
                    }

                    result.Add(str, rulePart);
                }
            }
            return(result);
        }
Beispiel #10
0
        /// <summary>
        /// Рекурсивно определяет все направляющие символы, которые может генерировать переданный элемент грамматики.
        /// Найденные результаты сохраняются в коллекцию guideChars.
        /// </summary>
        private void GetGuideChars(GrammarElement element, List <string> guideChars)
        {
            switch (element.Type)
            {
            case ElementType.NonTerminal:
                foreach (var rulePart in element.Rule.Right)
                {
                    GetGuideChars(rulePart.Elements.First(), guideChars);
                }
                break;

            case ElementType.Terminal:
                if (!guideChars.Contains(element.Characters))
                {
                    guideChars.Add(element.Characters);
                }
                break;

            case ElementType.Range:
                foreach (var c in element.Characters)
                {
                    if (!guideChars.Contains(c.ToString()))
                    {
                        guideChars.Add(c.ToString());
                    }
                }
                break;

            case ElementType.Empty:
                if (!guideChars.Contains(""))
                {
                    guideChars.Add("");
                }
                break;

            default:
                break;
            }
        }
Beispiel #11
0
        public override bool Equals(object obj)
        {
            GrammarElement elem = (GrammarElement)obj;

            return(Type == elem.Type && Characters == elem.Characters && Rule == elem.Rule);
        }
Beispiel #12
0
        /// <summary>
        /// Построить таблицу разбора по стартовому элементу грамматики.
        /// </summary>
        /// <param name="startedElement">Стартовый элемент грамматики.</param>
        internal Dictionary <GrammarElement, Dictionary <string, GrammarRulePart> > Build(GrammarElement startedElement)
        {
            Dictionary <GrammarElement, Dictionary <string, GrammarRulePart> > table = new Dictionary <GrammarElement, Dictionary <string, GrammarRulePart> >();

            List <GrammarElement> nonterminals = new List <GrammarElement> {
                startedElement
            };

            FindNonterminal(startedElement, nonterminals);

            foreach (var nonterm in nonterminals)
            {
                Dictionary <string, GrammarRulePart> map = FindUnfoldedWays(nonterm);
                table.Add(nonterm, map);
            }

            return(table);
        }