Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text.RegularExpressions;
- namespace lab1
- {
- using System.Globalization;
- /// <summary>
- /// Главный класс программы
- /// </summary>
- internal class Program
- {
- /// <summary>
- /// Главная функция
- /// </summary>
- /// <param name="args">Аргументы командной строки</param>
- private static int Main(string[] args)
- {
- const int N = 16; // Максимальная длина переменной (значащей части)
- string inputFilePath = "INPUT.TXT";
- if (args.Length == 1)
- {
- inputFilePath = args[0];
- }
- if (args.Length > 1)
- {
- Console.WriteLine("USAGE: lab1 <input file>");
- return 1;
- }
- using (TextWriter output = new StreamWriter(new FileStream("OUTPUT.TXT", FileMode.Create)))
- {
- try
- {
- string input;
- using (TextReader reader = new StreamReader(new FileStream(inputFilePath, FileMode.Open)))
- {
- input = reader.ReadToEnd();
- }
- // Регулярное выражение для последовательности пробельных символов
- const string spacesPattern = @"[\ \t\n\r]";
- const string numeric = @"([\+\-])?([0-9]+|\$[0-9A-Fa-f]+)";
- // Зарезервированные слова
- var reserved = new[] { "absolute", "and", "array", "asm", "begin", "case", "const", "constructor",
- "destructor", "div", "do", "downto", "else", "end", "file", "for", "function", "goto", "if",
- "implementation", "in", "inherited", "inline", "interface", "label", "mod", "nil", "not",
- "object", "of", "operator", "or", "packed", "procedure", "program", "record", "reintroduce",
- "repeat", "self", "set", "shl", "shr", "string", "then", "to", "type", "unit", "until", "uses",
- "var", "while", "with", "xor", "integer", "char", "boolean", "shortint", "byte", "smallint",
- "word", "cardinal", "longword", "longint", "int64", "qword", "real" };
- // Перечислимые типы данных
- var enumTypes = new[]
- {
- "integer",
- "char",
- "boolean",
- "shortint",
- "byte",
- "smallint",
- "word",
- "cardinal",
- "longword",
- "longint",
- "int64",
- "qword",
- "real"
- };
- // Неперечислимые типы данных
- var realTypes = new[]
- {
- "real"
- };
- // Шаблон для строки
- var stringPattern = string.Format(
- @"string((?<open>{0}*\[){0}*((?<strsize>{1})(?<-open>{0}*\]{0}*)?)?)?",
- spacesPattern,
- numeric);
- var types = new List<string>();
- types.AddRange(enumTypes);
- types.AddRange(realTypes);
- types.Add(stringPattern);
- // Шаблон для диапазона массива
- var rangePattern = string.Format(@"(({0}*{2}{0}*)|" + // Диапазон, заданный типом
- @"({0}*(?<startindex>{1}{0}*(?<start>))((\.\.{0}*)(?<endindex>{1}{0}*(?<-start>))?)?))",
- spacesPattern,
- numeric,
- string.Join("|", enumTypes));
- // Шаблон для массивов
- var arrayPattern = string.Format(@"(?<of>)" + // Определяем группу of
- @"((?(of)|(?!))" + // Ошибка если пропустили of в массиве массивов
- @"(?<-of>array){0}*" + // Ключевое слово array + пробелы + убираем of
- @"((?<open>\[{0}*)" + // Открывающая скобка
- @"({1}" +
- @"(?(start)(?!)|" +
- @"(?(comma)(?!)|" +
- @"((?<comma>{0}*\,{0}*)(?<-comma>{1})?)))*" +
- @"(?(comma)|(?(start)|(?<-open>{0}*\]{0}*)))?)?)?" + // Закрывающая скобка
- @"(?(open)|(?<of>of{0}*)?))*" + // Ключевое слово of + пробелы + проверяем скобки + определяем группу of
- @"((?(of)|(?!)){0}*(?<type-of>{2}))?", // Тип
- spacesPattern,
- rangePattern,
- string.Join("|", enumTypes.Concat(realTypes)) + "|" + stringPattern
- );
- // var arrayPattern = string.Format(
- // @"(?<of>)((?(of)|(?!))(?<-of>array){0}*" +
- // @"((?<open>{0}*\[)((({0}*(?<startindex>\d+(?<start>)){0}*(\.\.{0}*(?<endindex>\d+(?<-start>))?)?)|({0}*({1}){0}*))" +
- // @"{0}*((?(start)|((?<comma>\,)(({0}*(?<startindex>\d+(?<start>)){0}*(\.\.{0}*(?<endindex>\d+(?<-start>)(?<-comma>))?)?)|({0}*({1}){0}*(?<-comma>)))?)?)*" +
- // @"(?(start)|(?(comma)|(?<-open>{0}*\])))?)?)?)?{0}*(?(open)|(?<of>of{0}*)?))+" +
- // "((?(of)|(?!)){0}*(?<-of>{2}))?",
- // spacesPattern,
- // string.Join("|", enumTypes),
- // string.Join("|", enumTypes.Concat(realTypes)) + "|" + stringPattern
- //);
- types.Add(arrayPattern);
- // Получаем выражение для типов (по принципу или)
- var typesList = string.Join("|", types.Select(x =>
- string.Format(x, spacesPattern)));
- // Шаблон-группа для типов
- var typesPattern = string.Format(@"(?<type>{0})",
- typesList // Список типов
- );
- // Шаблон для переменной
- const string varPattern = @"(?<id>[A-Za-z_][0-9A-Za-z_]*)";
- // Шаблон для объявлений массивов
- //var arrayPattern = string.Format(
- // @"(?(open)(?!)|(?<open>{0}*\[){0}*((?!0{0}*\])\d+{0}*(?<-open>\]{0}*)?)?)*",
- // spacesPattern);
- // Шаблон для последующего списка переменных через запятую
- var varsPattern = string.Format(@"({0}*,{0}*{1})*",
- spacesPattern, // Выражение для пробельных символов
- varPattern // Выражение для переменной с учетом массивов
- );
- // Шаблон для списка определений переменных
- var varListPattern = string.Format("(?(eoln)(?<-eoln>)|(?!)){0}{1}", varPattern, varsPattern);
- // Шаблон для точки с запятой
- const string semicolonPattern = @"(?(type)(?<eoln-type>;)|(?!))?";
- // Шаблон регулярного выражения для проверки синтаксиса
- // {0} - Выражение для пробельных символов
- // {1} - Выражение для типов данных
- // {2} - Выражение для списка определений переменных
- // {3} - Выражение для точки с запятой
- const string pattern = @"(?<eoln>){0}*var{0}+({0}*{1}({0}*\:({0}*{2}({0}*{3}{0}*)?)?)?)*";
- // Регулярное выражение для проверки синтаксиса
- var checkRegex = new Regex(
- string.Format(
- pattern, // Шаблон выражения
- spacesPattern, // Выражение для пробельных символов
- varListPattern, // Выражение списка определений переменных
- arrayPattern, // Выражение для типов
- semicolonPattern // Выражение для точки с запятой
- ), RegexOptions.IgnoreCase);
- //checkRegex = new Regex(typesPattern);
- var match = checkRegex.Match(input);
- if (match.Length != input.Length)
- {
- int errorPosition;
- if (match.Index > 0)
- {
- errorPosition = 0;
- }
- else
- {
- errorPosition = match.Length;
- }
- var tillError = input.Substring(0, errorPosition).Split('\n');
- var lineNumber = tillError.Length > 0 ? tillError.Length : 1;
- var colNumber = tillError.Length > 0 ? tillError.Last().Length + 1 : 1;
- throw new Exception(string.Format("Syntax error at line {0} col {1}",
- lineNumber,
- colNumber));
- }
- // Список идентификаторов
- var identificators = new HashSet<string>();
- // Добавляем идентификаторы - имена переменных в множество
- foreach (var capture in match.Groups["id"].Captures.Cast<Capture>())
- {
- int errorPosition = capture.Index;
- var tillError = input.Substring(0, errorPosition).Split('\n');
- var lineNumber = tillError.Length > 0 ? tillError.Length : 1;
- var colNumber = tillError.Length > 0 ? tillError.Last().Length + 1 : 1;
- var value = capture.Value.ToLowerInvariant();
- if (value.Length > N)
- {
- value = value.Substring(0, N);
- }
- // Если идентификатор встретился повторно
- if (identificators.Contains(value))
- {
- // Выкидываем ошибку
- throw new Exception(string.Format(
- "duplicate identifier '{0}' at line {1} column {2}",
- value,
- lineNumber,
- colNumber));
- }
- // Если в качестве идентификатора используется зарезервированное слово
- if (reserved.Contains(value))
- {
- // Выкидываем ошибку
- throw new Exception(string.Format(
- "keyword '{0}' used as identifier at line {1} column {2}",
- value,
- lineNumber,
- colNumber));
- }
- identificators.Add(value);
- }
- // Проверяем длины строк
- foreach (var capture in match.Groups["strsize"].Captures.Cast<Capture>())
- {
- int errorPosition = capture.Index;
- var tillError = input.Substring(0, errorPosition).Split('\n');
- var lineNumber = tillError.Length > 0 ? tillError.Length : 1;
- var colNumber = tillError.Length > 0 ? tillError.Last().Length + 1 : 1;
- var size = ParseInt(capture.Value);
- // Если неправильный размер
- if (size == 0 || size > 255)
- {
- // Выкидываем ошибку
- throw new Exception(string.Format(
- "incorrect string size '{0}' at line {1} column {2}",
- capture.Value,
- lineNumber,
- colNumber));
- }
- }
- var starts = match.Groups["startindex"].Captures.Cast<Capture>().ToArray();
- var ends = match.Groups["endindex"].Captures.Cast<Capture>().ToArray();
- // Проверяем длины массивов
- for (int i = 0; i < starts.Length; i++)
- {
- var start = starts[i];
- var end = ends[i];
- int errorPosition = start.Index;
- var tillError = input.Substring(0, errorPosition).Split('\n');
- var lineNumber = tillError.Length > 0 ? tillError.Length : 1;
- var colNumber = tillError.Length > 0 ? tillError.Last().Length + 1 : 1;
- // Если неправильный размер
- if (ParseInt(start.Value) > ParseInt(end.Value))
- {
- // Выкидываем ошибку
- throw new Exception(string.Format(
- "incorrect array size '{0}..{1}' at line {2} column {3}",
- start.Value,
- end.Value,
- lineNumber,
- colNumber));
- }
- }
- output.WriteLine("Success");
- }
- catch (Exception ex)
- {
- output.WriteLine("Error: {0}", ex.Message);
- }
- }
- return 0;
- }
- public static int ParseInt(string value)
- {
- if (value[0] == '$')
- {
- return int.Parse(value.Substring(1), NumberStyles.AllowHexSpecifier);
- }
- else
- {
- return int.Parse(value);
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement