Guest User

Regex pascal parsing

a guest
Dec 4th, 2017
224
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text.RegularExpressions;
  6.  
  7. namespace lab1
  8. {
  9.     using System.Globalization;
  10.  
  11.     /// <summary>
  12.     /// Главный класс программы
  13.     /// </summary>
  14.     internal class Program
  15.     {
  16.         /// <summary>
  17.         /// Главная функция
  18.         /// </summary>
  19.         /// <param name="args">Аргументы командной строки</param>
  20.         private static int Main(string[] args)
  21.         {
  22.             const int N = 16;   // Максимальная длина переменной (значащей части)
  23.  
  24.             string inputFilePath = "INPUT.TXT";
  25.  
  26.             if (args.Length == 1)
  27.             {
  28.                 inputFilePath = args[0];
  29.             }
  30.             if (args.Length > 1)
  31.             {
  32.                 Console.WriteLine("USAGE: lab1 <input file>");
  33.                 return 1;
  34.             }
  35.  
  36.             using (TextWriter output = new StreamWriter(new FileStream("OUTPUT.TXT", FileMode.Create)))
  37.             {
  38.                 try
  39.                 {
  40.                     string input;
  41.                     using (TextReader reader = new StreamReader(new FileStream(inputFilePath, FileMode.Open)))
  42.                     {
  43.                         input = reader.ReadToEnd();
  44.                     }
  45.  
  46.                     // Регулярное выражение для последовательности пробельных символов
  47.                     const string spacesPattern = @"[\ \t\n\r]";
  48.                     const string numeric = @"([\+\-])?([0-9]+|\$[0-9A-Fa-f]+)";
  49.  
  50.                     // Зарезервированные слова
  51.                     var reserved = new[] { "absolute", "and", "array", "asm", "begin", "case", "const", "constructor",
  52.                         "destructor", "div", "do", "downto", "else", "end", "file", "for", "function", "goto", "if",
  53.                         "implementation", "in", "inherited", "inline", "interface", "label", "mod", "nil", "not",
  54.                         "object", "of", "operator", "or", "packed", "procedure", "program", "record", "reintroduce",
  55.                         "repeat", "self", "set", "shl", "shr", "string", "then", "to", "type", "unit", "until", "uses",
  56.                         "var", "while", "with", "xor", "integer", "char", "boolean", "shortint", "byte", "smallint",
  57.                         "word", "cardinal", "longword", "longint", "int64", "qword", "real" };
  58.  
  59.                     // Перечислимые типы данных
  60.                     var enumTypes = new[]
  61.                     {
  62.                         "integer",
  63.                         "char",
  64.                         "boolean",
  65.                         "shortint",
  66.                         "byte",
  67.                         "smallint",
  68.                         "word",
  69.                         "cardinal",
  70.                         "longword",
  71.                         "longint",
  72.                         "int64",
  73.                         "qword",
  74.                         "real"
  75.                     };
  76.  
  77.                     // Неперечислимые типы данных
  78.                     var realTypes = new[]
  79.                     {
  80.                         "real"
  81.                     };
  82.  
  83.                     // Шаблон для строки
  84.                     var stringPattern = string.Format(
  85.                         @"string((?<open>{0}*\[){0}*((?<strsize>{1})(?<-open>{0}*\]{0}*)?)?)?",
  86.                         spacesPattern,
  87.                         numeric);
  88.  
  89.                     var types = new List<string>();
  90.                     types.AddRange(enumTypes);
  91.                     types.AddRange(realTypes);
  92.                     types.Add(stringPattern);
  93.  
  94.                     // Шаблон для диапазона массива
  95.                     var rangePattern = string.Format(@"(({0}*{2}{0}*)|" +       // Диапазон, заданный типом
  96.                         @"({0}*(?<startindex>{1}{0}*(?<start>))((\.\.{0}*)(?<endindex>{1}{0}*(?<-start>))?)?))",
  97.                         spacesPattern,
  98.                         numeric,
  99.                         string.Join("|", enumTypes));
  100.  
  101.                     // Шаблон для массивов
  102.                     var arrayPattern = string.Format(@"(?<of>)" +               // Определяем группу of
  103.                             @"((?(of)|(?!))" +                                  // Ошибка если пропустили of в массиве массивов
  104.                             @"(?<-of>array){0}*" +                              // Ключевое слово array + пробелы + убираем of
  105.                             @"((?<open>\[{0}*)" +                               // Открывающая скобка
  106.                             @"({1}" +
  107.                             @"(?(start)(?!)|" +
  108.                             @"(?(comma)(?!)|" +
  109.                             @"((?<comma>{0}*\,{0}*)(?<-comma>{1})?)))*" +
  110.                             @"(?(comma)|(?(start)|(?<-open>{0}*\]{0}*)))?)?)?" +                       // Закрывающая скобка    
  111.                             @"(?(open)|(?<of>of{0}*)?))*" +                     // Ключевое слово of + пробелы + проверяем скобки + определяем группу of
  112.                             @"((?(of)|(?!)){0}*(?<type-of>{2}))?",             // Тип
  113.                             spacesPattern,
  114.                             rangePattern,
  115.                             string.Join("|", enumTypes.Concat(realTypes)) + "|" + stringPattern
  116.                         );
  117.  
  118.  
  119.                    // var arrayPattern = string.Format(
  120.                    //    @"(?<of>)((?(of)|(?!))(?<-of>array){0}*" +
  121.                    //    @"((?<open>{0}*\[)((({0}*(?<startindex>\d+(?<start>)){0}*(\.\.{0}*(?<endindex>\d+(?<-start>))?)?)|({0}*({1}){0}*))" +
  122.                    //    @"{0}*((?(start)|((?<comma>\,)(({0}*(?<startindex>\d+(?<start>)){0}*(\.\.{0}*(?<endindex>\d+(?<-start>)(?<-comma>))?)?)|({0}*({1}){0}*(?<-comma>)))?)?)*" +
  123.                    //    @"(?(start)|(?(comma)|(?<-open>{0}*\])))?)?)?)?{0}*(?(open)|(?<of>of{0}*)?))+" +
  124.                    //    "((?(of)|(?!)){0}*(?<-of>{2}))?",
  125.                    //    spacesPattern,
  126.                    //    string.Join("|", enumTypes),
  127.                    //    string.Join("|", enumTypes.Concat(realTypes)) + "|" + stringPattern
  128.                    //);
  129.  
  130.                     types.Add(arrayPattern);
  131.  
  132.                     // Получаем выражение для типов (по принципу или)
  133.                     var typesList = string.Join("|", types.Select(x =>
  134.                         string.Format(x, spacesPattern)));
  135.  
  136.                     // Шаблон-группа для типов
  137.                     var typesPattern = string.Format(@"(?<type>{0})",
  138.                         typesList      // Список типов
  139.                         );
  140.  
  141.                     // Шаблон для переменной
  142.                     const string varPattern = @"(?<id>[A-Za-z_][0-9A-Za-z_]*)";
  143.  
  144.                     // Шаблон для объявлений массивов
  145.                     //var arrayPattern = string.Format(
  146.                     //    @"(?(open)(?!)|(?<open>{0}*\[){0}*((?!0{0}*\])\d+{0}*(?<-open>\]{0}*)?)?)*",
  147.                     //    spacesPattern);
  148.                     // Шаблон для последующего списка переменных через запятую
  149.                     var varsPattern = string.Format(@"({0}*,{0}*{1})*",
  150.                         spacesPattern,  // Выражение для пробельных символов
  151.                         varPattern      // Выражение для переменной с учетом массивов
  152.                         );
  153.  
  154.                     // Шаблон для списка определений переменных
  155.                     var varListPattern = string.Format("(?(eoln)(?<-eoln>)|(?!)){0}{1}", varPattern, varsPattern);
  156.  
  157.                     // Шаблон для точки с запятой
  158.                     const string semicolonPattern = @"(?(type)(?<eoln-type>;)|(?!))?";
  159.  
  160.                     // Шаблон регулярного выражения для проверки синтаксиса
  161.                     // {0} - Выражение для пробельных символов
  162.                     // {1} - Выражение для типов данных
  163.                     // {2} - Выражение для списка определений переменных
  164.                     // {3} - Выражение для точки с запятой
  165.                     const string pattern = @"(?<eoln>){0}*var{0}+({0}*{1}({0}*\:({0}*{2}({0}*{3}{0}*)?)?)?)*";
  166.  
  167.                     // Регулярное выражение для проверки синтаксиса
  168.                     var checkRegex = new Regex(
  169.                         string.Format(
  170.                             pattern,            // Шаблон выражения
  171.                             spacesPattern,      // Выражение для пробельных символов
  172.                             varListPattern,       // Выражение списка определений переменных
  173.                             arrayPattern,     // Выражение для типов
  174.                             semicolonPattern    // Выражение для точки с запятой
  175.                             ), RegexOptions.IgnoreCase);
  176.  
  177.                     //checkRegex = new Regex(typesPattern);
  178.                     var match = checkRegex.Match(input);
  179.                     if (match.Length != input.Length)
  180.                     {
  181.                         int errorPosition;
  182.                         if (match.Index > 0)
  183.                         {
  184.                             errorPosition = 0;
  185.                         }
  186.                         else
  187.                         {
  188.                             errorPosition = match.Length;
  189.                         }
  190.  
  191.                         var tillError = input.Substring(0, errorPosition).Split('\n');
  192.                         var lineNumber = tillError.Length > 0 ? tillError.Length : 1;
  193.                         var colNumber = tillError.Length > 0 ? tillError.Last().Length + 1 : 1;
  194.  
  195.                         throw new Exception(string.Format("Syntax error at line {0} col {1}",
  196.                             lineNumber,
  197.                             colNumber));
  198.                     }
  199.  
  200.                     // Список идентификаторов
  201.                     var identificators = new HashSet<string>();
  202.  
  203.                      // Добавляем идентификаторы - имена переменных в множество
  204.                     foreach (var capture in match.Groups["id"].Captures.Cast<Capture>())
  205.                     {
  206.                         int errorPosition = capture.Index;
  207.                         var tillError = input.Substring(0, errorPosition).Split('\n');
  208.                         var lineNumber = tillError.Length > 0 ? tillError.Length : 1;
  209.                         var colNumber = tillError.Length > 0 ? tillError.Last().Length + 1 : 1;
  210.  
  211.                         var value = capture.Value.ToLowerInvariant();
  212.                         if (value.Length > N)
  213.                         {
  214.                             value = value.Substring(0, N);
  215.                         }
  216.  
  217.                         // Если идентификатор встретился повторно
  218.                         if (identificators.Contains(value))
  219.                         {
  220.                             // Выкидываем ошибку
  221.                             throw new Exception(string.Format(
  222.                                 "duplicate identifier '{0}' at line {1} column {2}",
  223.                                 value,
  224.                                 lineNumber,
  225.                                 colNumber));
  226.                         }
  227.                         // Если в качестве идентификатора используется зарезервированное слово
  228.                         if (reserved.Contains(value))
  229.                         {
  230.                             // Выкидываем ошибку
  231.                             throw new Exception(string.Format(
  232.                                 "keyword '{0}' used as identifier at line {1} column {2}",
  233.                                 value,
  234.                                 lineNumber,
  235.                                 colNumber));
  236.                         }
  237.  
  238.                         identificators.Add(value);
  239.                     }
  240.  
  241.                     // Проверяем длины строк
  242.                     foreach (var capture in match.Groups["strsize"].Captures.Cast<Capture>())
  243.                     {
  244.                         int errorPosition = capture.Index;
  245.                         var tillError = input.Substring(0, errorPosition).Split('\n');
  246.                         var lineNumber = tillError.Length > 0 ? tillError.Length : 1;
  247.                         var colNumber = tillError.Length > 0 ? tillError.Last().Length + 1 : 1;
  248.  
  249.                         var size = ParseInt(capture.Value);
  250.  
  251.                         // Если неправильный размер
  252.                         if (size == 0 || size > 255)
  253.                         {
  254.                             // Выкидываем ошибку
  255.                             throw new Exception(string.Format(
  256.                                 "incorrect string size '{0}' at line {1} column {2}",
  257.                                 capture.Value,
  258.                                 lineNumber,
  259.                                 colNumber));
  260.                         }
  261.                     }
  262.  
  263.                     var starts = match.Groups["startindex"].Captures.Cast<Capture>().ToArray();
  264.                     var ends = match.Groups["endindex"].Captures.Cast<Capture>().ToArray();
  265.  
  266.                     // Проверяем длины массивов
  267.                     for (int i = 0; i < starts.Length; i++)
  268.                     {
  269.                         var start = starts[i];
  270.                         var end = ends[i];
  271.                         int errorPosition = start.Index;
  272.                         var tillError = input.Substring(0, errorPosition).Split('\n');
  273.                         var lineNumber = tillError.Length > 0 ? tillError.Length : 1;
  274.                         var colNumber = tillError.Length > 0 ? tillError.Last().Length + 1 : 1;
  275.  
  276.                         // Если неправильный размер
  277.                         if (ParseInt(start.Value) > ParseInt(end.Value))
  278.                         {
  279.                             // Выкидываем ошибку
  280.                             throw new Exception(string.Format(
  281.                                 "incorrect array size '{0}..{1}' at line {2} column {3}",
  282.                                 start.Value,
  283.                                 end.Value,
  284.                                 lineNumber,
  285.                                 colNumber));
  286.                         }
  287.                     }
  288.  
  289.                     output.WriteLine("Success");
  290.                 }
  291.                 catch (Exception ex)
  292.                 {
  293.                     output.WriteLine("Error: {0}", ex.Message);
  294.                 }
  295.             }
  296.  
  297.             return 0;
  298.         }
  299.  
  300.         public static int ParseInt(string value)
  301.         {
  302.             if (value[0] == '$')
  303.             {
  304.                 return int.Parse(value.Substring(1), NumberStyles.AllowHexSpecifier);
  305.             }
  306.             else
  307.             {
  308.                 return int.Parse(value);
  309.             }
  310.         }
  311.     }
  312. }
RAW Paste Data