Форум программистов, компьютерный форум, киберфорум
Наши страницы
Delphi для начинающих
Войти
Регистрация
Восстановить пароль
 
Кирилл_В
4 / 4 / 3
Регистрация: 29.10.2015
Сообщений: 39
#1

Используя стек, проверить правильность вложений операторных скобок (begin/end) - Delphi

25.01.2016, 19:27. Просмотров 377. Ответов 5
Метки нет (Все метки)


http://www.cyberforum.ru/delphi-beginners/thread794107.html
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
25.01.2016, 19:27
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Используя стек, проверить правильность вложений операторных скобок (begin/end) (Delphi):

Проверить правильность расстановки круглых скобок
помогите пожалуйста. дан текст в котором могут быть круглые скобки. Проверить...

Проверить правильность расстановки скобок
Помогите написать программу.Проверить правильно ли в операторе...

Проверить правильность расстановки круглых и квадратных скобок в выражениях
задание дана строка символов проверить правильность расстановки круглых и...

Проверку соблюдения баланса операторных скобок
Задан текст,написанный и находящийся в файле.Произвети проверку соблюдения...

begin...end тупик!
Здравствуйте!Сново тупик у меня!При решение ax^4+bx^2+c=0 у меня программа...

5
Mawrat
12821 / 5729 / 1700
Регистрация: 19.09.2009
Сообщений: 8,807
27.01.2016, 11:57 #2
Лучший ответ Сообщение было отмечено Кирилл_В как решение

Решение

Цитата Сообщение от Кирилл_В Посмотреть сообщение
В файле находится текст программы на pascal. используя стек проверить правильность вложений операторных скобок (begin/end)...
Решение с использованием стека, построенного на динамическом однонаправленном списке.
Программа предназначена для исследования исходных текстов программ и модулей Pascal и Delphi - *.pas и *.dpr.
Для правильной работы программы должно выполняться условие:
- Слова UNIT, RECORD, CLASS, OBJECT, BEGIN, END, с любым регистром букв, не должны находиться внутри строковых литералов или комментариев.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
program Project1;
 
{$APPTYPE CONSOLE}
 
uses
  SysUtils, Windows;
 
type
  //Тип основных данных.
  TData = String;
  //Указатель на элемент списка (в данном случае - стека).
  TPElem = ^TElem;
  //Элемент списка.
  TElem = record
    Data : TData;
    PNext : TPElem; //Указатель на следующий элемент списка.
  end;
 
//Добавление элемента на вершину стека.
procedure Push(var aPStack : TPElem; const aData : TData);
var
  PElem : TPElem;
begin
  New(PElem);
  PElem^.Data := aData;
  PElem^.PNext := aPStack;
  aPStack := PElem;
end;
 
{Изъятие элемента с вершины стека.
Если стек не пуст, то с вершины стека изымается элемент и возвращается
через параметр aData. В этом случае, функция возвращает значение True.
Если стек пуст, то операция отменяется, а функция возвращает значение False.}
function Pop(var aPStack : TPElem; var aData : TData) : Boolean;
var
  PDel : TPElem;
begin
  Pop := False;
  if aPStack <> nil then
  begin
    PDel := aPStack;
    aData := PDel^.Data;
    aPStack := aPStack^.PNext;
    Dispose(PDel);
    Pop := True;
  end;
end;
 
//Освобождение памяти, занятой под стек (очистка стека).
procedure StFree(var aPStack : TPElem);
var
  Data : TData;
begin
  while Pop(aPStack, Data) do;
end;
 
const
  //Относительный путь файла. (Относительно директория, в котором расположен исполняемый файл программы).
  Fn = 'files\project1.dpr';
  //Fn = 'files\Unit1.pas';
  //Множество разделителей.
  D = ['.', ',', ':', ';', '-', '+', '*', '/', '(', ')', '[', ']', '{', '}',
    '''', ' ', #9, #10, #13];
 
var
  f : TextFile;
  PSt : TPElem;
  i, L, P, Len, LenW : Integer;
  S : String;
  Sw : TData;
begin
  {Переключение окна консоли на кодовую страницу CP1251 (Win-1251).
  Если после переключения русские буквы показываются неверно, то
  следует открыть системное меню консольного окна - щелчком мыши в левом
  верхнем углу окна консоли и выбрать:
  Свойства - вкладка "Шрифт" - выбрать шрифт: "Lucida Console" или "Consolas".}
  SetConsoleCP(1251);
  SetConsoleOutputCP(1251);
 
  PSt := nil; //Начальная инициализация стека.
 
  repeat
    Writeln('------------------------------');
    Writeln('Файл: ', Fn);
    //ExtractFilePath(ParamStr(0)) - полный путь директория, в котором лежит исполняемый файл программы.
    AssignFile(f, ExtractFilePath(ParamStr(0)) + Fn);
    Reset(f);
    L := 0;   //Строка, на которой обнаружена ошибка.
    P := 0;   //Позиция (в пределах строки), на которой обнаружена ошибка.
    while not Eof(f) do //Если не конец файла, то продолжаем цикл.
    begin
      Readln(f, S);     //Читаем очередную строку из файла.
      Inc(L);           //Номер очередной строки.
      Len := Length(S); //Длина строки.
      LenW := 0;        //Длина лексемы.
      for i := 1 to Length(S) do //Перебор всех символов строки.
        if not (S[i] in D) then  //Если символ не является разделителем.
        begin
          Inc(LenW); //Учёт текущего символа в длине лексемы.
          if (i = Len) or (S[i + 1] in D) then //Если обнаружен конец лексемы.
          begin
            Sw := AnsiUpperCase(Copy(S, i - LenW + 1, LenW)); //Выделяем лексему и преобразуем её буквы к верхнему регистру.
            if (Sw = 'BEGIN') or (Sw = 'RECORD') or (Sw = 'CLASS')
              or (Sw = 'OBJECT') or (Sw = 'UNIT')
            then                    //Если обнаружена открывающая скобка.
              Push(PSt, Sw)         //Помещаем открывающую скобку в стек.
            else if Sw = 'END' then //Если обнаружена закрывающая скобка.
            begin
              if not Pop(PSt, Sw) then //Берём с вершины стека открывающую скобку.
              begin
                P := i - LenW + 1;
                Break;
              end;
            end;
            LenW := 0; //Обнуление длины лексемы.
          end;
        end;
      if P > 0 then
        Break;
    end;
    CloseFile(f);
    
    if P > 0 then
      Writeln('Ошибка! Нет соответствующей открывающей скобки. Строка: ', L, ', Позиция: ', P)
    else if PSt <> nil then
      Writeln('Ошибка! Открывающих скобок больше, чем закрывающих.')
    else
      Writeln('Скобки расставлены правильно!');
 
    StFree(PSt); //Освобождение памяти, занятой для стека.
    Writeln('-----');
    Write('Повторить - Enter. Выход - любой символ + Enter. ');
    Readln(S);
  until S <> '';
end.
1
Кирилл_В
4 / 4 / 3
Регистрация: 29.10.2015
Сообщений: 39
28.01.2016, 22:04  [ТС] #3
Спасибо большое, останется только в полноэкранку перевести.
0
Mawrat
12821 / 5729 / 1700
Регистрация: 19.09.2009
Сообщений: 8,807
29.01.2016, 08:04 #4
Для переделки в GUI-приложение (GUI Graphic User Interface), надо заменить консольный вывод (Writeln) на вывод в экземпляр TMemo, например.
Например, так. На форму надо положить компоненты:
Delphi
1
2
3
    Button1: TButton;
    Edit1: TEdit;
    Memo1: TMemo;
В Edit1 пользователь должен ввести относительный путь файла (относительно директория, в котором расположен исполняемый файл программы). В Memo1 осуществляется вывод программы.
Для кнопки Button1 надо создать обработчик события OnClick - TForm1.Button1Click(). Код раздела implementation в модуле оформить следующим образом:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
implementation
 
{$R *.dfm}
 
type
  //Тип основных данных.
  TData = String;
  //Указатель на элемент списка (в данном случае - стека).
  TPElem = ^TElem;
  //Элемент списка.
  TElem = record
    Data : TData;
    PNext : TPElem; //Указатель на следующий элемент списка.
  end;
 
//Добавление элемента на вершину стека.
procedure Push(var aPStack : TPElem; const aData : TData);
var
  PElem : TPElem;
begin
  New(PElem);
  PElem^.Data := aData;
  PElem^.PNext := aPStack;
  aPStack := PElem;
end;
 
{Изъятие элемента с вершины стека.
Если стек не пуст, то с вершины стека изымается элемент и возвращается
через параметр aData. В этом случае, функция возвращает значение True.
Если стек пуст, то операция отменяется, а функция возвращает значение False.}
function Pop(var aPStack : TPElem; var aData : TData) : Boolean;
var
  PDel : TPElem;
begin
  Pop := False;
  if aPStack <> nil then
  begin
    PDel := aPStack;
    aData := PDel^.Data;
    aPStack := aPStack^.PNext;
    Dispose(PDel);
    Pop := True;
  end;
end;
 
//Освобождение памяти, занятой под стек (очистка стека).
procedure StFree(var aPStack : TPElem);
var
  Data : TData;
begin
  while Pop(aPStack, Data) do;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
const
  //Множество разделителей.
  D = ['.', ',', ':', ';', '-', '+', '*', '/', '(', ')', '[', ']', '{', '}',
    '''', ' ', #9, #10, #13];
var
  f : TextFile;
  PSt : TPElem;
  i, L, P, Len, LenW : Integer;
  S, FileName : String;
  Sw : TData;
begin
  PSt := nil; //Начальная инициализация стека.
 
  Memo1.Lines.Add('------------------------------');
  //ExtractFilePath(ParamStr(0)) - полный путь директория, в котором лежит исполняемый файл программы.
  //Относительный путь (относительно директория, в котором лежит исполняемый файл программы)
  //указан в Edit1.
  FileName := ExtractFilePath(ParamStr(0)) + Edit1.Text;
  Memo1.Lines.Add('Файл: ' + FileName);
  Memo1.Lines.Add('Проверка операторных скобок.');
  AssignFile(f, FileName);
  Reset(f);
  L := 0; //Строка, на которой обнаружена ошибка.
  P := 0; //Позиция (в пределах строки), на которой обнаружена ошибка.
  while not Eof(f) do //Если не конец файла, то продолжаем цикл.
  begin
    Readln(f, S);     //Читаем очередную строку из файла.
    Inc(L);           //Номер очередной строки.
    Len := Length(S); //Длина строки.
    LenW := 0;        //Длина лексемы.
    for i := 1 to Length(S) do //Перебор всех символов строки.
      if not (S[i] in D) then  //Если символ не является разделителем.
      begin
        Inc(LenW); //Учёт текущего символа в длине лексемы.
        if (i = Len) or (S[i + 1] in D) then //Если обнаружен конец лексемы.
        begin
          Sw := AnsiUpperCase(Copy(S, i - LenW + 1, LenW)); //Выделяем лексему и преобразуем её буквы к верхнему регистру.
          if (Sw = 'BEGIN') or (Sw = 'RECORD') or (Sw = 'CLASS')
            or (Sw = 'OBJECT') or (Sw = 'UNIT')
          then                    //Если обнаружена открывающая скобка.
            Push(PSt, Sw)         //Помещаем открывающую скобку в стек.
          else if Sw = 'END' then //Если обнаружена закрывающая скобка.
          begin
            if not Pop(PSt, Sw) then //Берём с вершины стека открывающую скобку.
            begin
              P := i - LenW + 1;
              Break;
            end;
          end;
          LenW := 0;        //Обнуление длины лексемы.
        end;
      end;
    if P > 0 then
      Break;
  end;
  CloseFile(f);
 
  if P > 0 then
    Memo1.Lines.Add('Ошибка! Нет соответствующей открывающей скобки. Строка: '
      + IntToStr(L) + ', Позиция: ' + IntToStr(P))
  else if PSt <> nil then
    Memo1.Lines.Add('Ошибка! Открывающих скобок больше, чем закрывающих.')
  else
    Memo1.Lines.Add('Скобки расставлены правильно!');
 
  StFree(PSt); //Освобождение памяти, занятой для стека.
  Memo1.Lines.Add('-----');
  Memo1.Lines.Add('Память, выделенная для стека - освобождена.');
end;
 
end.
1
Кирилл_В
4 / 4 / 3
Регистрация: 29.10.2015
Сообщений: 39
01.02.2016, 22:33  [ТС] #5
Помогите пожалуйста разобраться, как подключить текстовый файл?

Добавлено через 2 часа 13 минут
А вроде разобрался. Спасибо еще раз.
0
Mawrat
12821 / 5729 / 1700
Регистрация: 19.09.2009
Сообщений: 8,807
01.02.2016, 22:34 #6
А для чего здесь текстовый файл? Или имеется в виду входной файл с исходным кодом, который надо анализировать? Имя входного файла задаётся в Edit1 - надо указать путь относительно директория, в котором лежит исполняемый файл программы. Т. е., например, если входной файл лежит в одном директории с программой, то относительный путь файла будет совпадать с его именем.
0
01.02.2016, 22:34
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.02.2016, 22:34
Привет! Вот еще темы с решениями:

Теория BEGIN..END;
Снова здрасьте! Довольно часто я встречаю примеры кода, подобные этому var...

Ошибка при if end then begin
При выполнении проверки - ошибка ! В чем может быть дело ? if...

XE8 Begin-end подсветка
Доброе утро. Работаю в XE8 недавно, при разборе чужого кода столкнулся с кучей...

Сворачивание блоков begin end на RAD XE5
Недавно психанул и вместо старого 7 делфи поставил себе ХЕ5, в целом доволен,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru