Помощь - Поиск - Пользователи - Календарь
Полная версия: Форматирование исходников
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
Jaxx
Вот я опять и появился. Теперь у меня задание еще более интересное. Смысл следующий: есть текстовый файл с исходником программы на Паскале, нужно-
1) первые буквы служебных слов сделать заглавными
2) текст комментариев заменить на их номер по порядку
3) переписать текст в новый файл с удалением лишних пробелов.
Я понимаю, что тут может быть только один путь решения: создать массив (или множество) служебных слов, затем считывать текст файла посимвольно (т.к. служебные слова обязательно должны быть отделены от других пробелами или знаками препинания). Я прав? С комментариями попроще: просто найти символ '{' и проверить следующий после него, и если это не '$' то удалить все символы начиная с этого до символа '}'. Удаление пробелов еще проще. Но с первой частью задания у меня небольшие трудности. Решайте! :yes:

В следующий раз давайте более подходящий заголовок
volvo
Цитата(Jaxx @ 6.04.05 11:26)
Но с первой частью задания у меня небольшие трудности. Решайте! :yes:

Посмотри вот эту мою программку... Программа форматирования Паскаль-программ
Может, она натолкнет тебя на идею? ;) Кстати, я выкладывал на форум и программу удаления комментариев. Попробуй поискать и чуть-чуть подправить ее ...

Кстати, не все так просто:
Цитата
С комментариями попроще: просто найти символ '{' и проверить следующий после него, и если это не '$' то удалить все символы начиная с этого до символа '}'.
Есть еще комментарии вида "(* ... *)" smile.gif
Jaxx
Насчет (* *) я знаю. Тут смысл будет такой же, только символы другие. А тему я правильно назвал, ибо редактироваться будет текстовый файл, а не исходник. А что если первое задание поменять на немного другое: вывести на экран использованные в тексте служебные слова и для каждого из них вывести количество вхождений в текст.
volvo
Цитата(Jaxx @ 6.04.05 11:44)
Насчет (* *) я знаю. Тут смысл будет такой же, только символы другие.
А ты в курсе, что есть Nested Comments, что усложняет работу? Ты бы попробовал, а потом посмотрим, просто это, или не очень...

Цитата(Jaxx @ 6.04.05 11:44)
А тему я правильно назвал, ибо редактироваться будет текстовый файл, а не исходник.
Но это не просто текстовый файл, а файл содержащий исходник паскаль-программы. Или тебе не важно, что твоя программа НЕ будет компилироваться после обработки? А если важно, то тема должна называться так, как она называется сейчас...

Цитата(Jaxx @ 6.04.05 11:44)
А что если первое задание поменять на немного другое: вывести на экран использованные в тексте служебные слова и для каждого из них вывести количество вхождений в текст.
Это катастрофически упрощает задачу, т.к. тебе не надо заменять слова в тексте, а достаточно просто запомнить их...
А вот прежде чем запостить что-нибудь, надо решить, что ИМЕННО тебе нужно. Потому как если ты и далее будешь менять условия, то зачем надо начинать думать?
Jaxx
Ладно, я все понял. Условие задачи остается начальное. У меня основная сложность заключается в поиске служебных слов. Я составил массив этих слов и массив разделителей (пробел, точка, точка с запятой и т.д.), но не знаю как в массив разделителей добавить знак конца строки и табуляции. Во-вторых, у меня вот какой вопрос (сразу говорю - тупой), файловую переменную какого типа нужно брать- Text? А вашу программку еще не смотрел - я на работе, а тут Паскаля нетути.
Altair
Jaxx, привет! Почти год тебя не было! С возвращением! :thanks:

Цитата
файловую переменную какого типа нужно брать- Text?

Да в принципе любую, но с TEXT будет проще работать smile.gif
Так что ее.

Цитата
но не знаю как в массив разделителей добавить знак конца строки и табуляции.

Ну во-первых проще взять множетсво (и работать с ним проще будет в данном случае, и памяти меньше съест smile.gif )
Во-вторых - зачем тебе знак конца строки? такого нету вообще smile.gif

Что до задачи, то алгоритм можно такой выбрать - разбить текс на слова (алгоритм ф FAQ"e моджернизировать что бьы только слова зарезервированные - из списка брал).
И делаешь по заданию.
Jaxx
Привет и тебе, OlegZ !!! :thanks:
У меня ни на что нет времени. Значит, переменная будет Text. Понял. Насчет конца строки тоже понял. А что с табуляцией? Как ее в массив (множество) записать?
Jaxx
Я тут вот чего-то написал, правда нифига не работает. Гляньте, да поправьте, а то вроде с виду все должно работать (по крайней мере. идея симпатичная).

uses crt;
const
 cycle:array[1..11] of string=('do','downto','else','for','if','in','repeat','then','to','until','while');
 base:array[1..12] of string=('begin','else','end','function','goto','label','not','or','procedure','program','uses','var');
 spec1:array[1..8] of string=('and','asm','constructor','destructor','external','forward','implementation','inline');
 spec2:array[1..7] of string=('interface','interrupt','nil','object','shl','shr','packed');
 types:array[1..9] of string=('array','case','const','file','record','set','string','type','unit');
 math:array[1..6] of string=('div','mod','of','or','with','xor');
 direct:array[1..6] of string=('absolute','assembler','far','near','private','virtual');
 symbols:array[1..14] of char=('{','}','(',')','=',' ',';',':','+','-','/','*','.',',');
var
 f,f_new:text;
 s,s1:string;
 i:byte;
 kol:byte;
 mas:array[1..59] of string;
 mas2:array[1..59] of byte;
 temp:array[1..59] of string;

procedure massiv(cycle,base,spec1,spec2,types,math,direct:array of string);
var mas2:array [1..59] of byte;
   begin
   for i:=1 to 59 do
    temp[i]:='';
   for i:=1 to 11 do
    mas[i]:=cycle[i];
    for i:=11 to 23 do
    mas[i]:=base[i];
    for i:=23 to 31 do
    mas[i]:=spec1[i];
    for i:=31 to 38 do
    mas[i]:=spec2[i];
    for i:=38 to 47 do
    mas[i]:=types[i];
    for i:=47 to 53 do
    mas[i]:=math[i];
    for i:=53 to 59 do
    mas[i]:=direct[i];
   for i:=1 to 59 do
   mas2[i]:=kol;
end;

begin
clrscr;
 writeln('Vvedite imya faila: ');
 readln(s);
 assign(f,s);
 {$I-} reset(f); {$I+}
  if ioresult<>0 then writeln('Cannot open file to read!');
 writeln('Vvedite imya novogo faila: ');
 readln(s1);
 assign(f_new,s1);
 {$I-} rewrite(f_new); {$I+}
  if ioresult<>0 then writeln('Cannot create file to input!');
  massiv(cycle,base,spec1,spec2,types,math,direct);
  s:=''; s1:='';
  i:=0; kol:=0;
 while not seekeof(f) do begin
readln(f,s);
massiv(cycle,base,spec1,spec2,types,math,direct);
 if s=symbols[i]+mas[i]+symbols[i] then begin
    mas2[i]:=kol+1;
    writeln('slovo' ,mas[i],' vstrechaetsia ',mas2[i],' raz');
    end;
 end;
readln;
end.

Jaxx
Ну так что, никто мне не поможет?! Скажите, в где у меня ошибка! Только не говорите, что в генах...Главная проблема - в поиске и определении служебных слов. Остальное - сам справлюсь (по крайней мере постараюсь).
volvo
Jaxx, ты ходил по первой ссылке, которую я тебе дал? Там что, по-твоему служебные слова для красоты в массив собраны? Наверное не просто так, а все-таки там тоже ищутся вхождения служебных слов. Читается файл строка за строкой, каждая строка разбивается на токены, и проверяешь, является ли очередной токен служебным словом. Как - смотри в том исходнике...

А в твоей программе есть проблема:

const
base:array[1..12] of string=('begin','else','end','function','goto','label','not',
'or','procedure','program','uses','var');
spec1:array[1..8] of string=('and','asm','constructor','destructor','external',
'forward','implementation','inline');
...
procedure massiv(cycle,base,spec1,spec2,types,math,direct:array of string);
...
begin
...
for i:=11 to 23 do
 mas[i]:=base[i]; { а что, в Base имеется элемент с индексом > 12 ??? }
for i:=23 to 31 do
 mas[i]:=spec1[i]; { а в Spec1 - с индексом > 8 ??? }
...
{ и так далее... }
end;
Altair
А зачем разбивать на слова?
вот еще способ без разбиения, прога во всех зарез. словах первую букуву делает большой.
var
zar:array[1..51] of string[15];

function progwork(s:string):string;
var
i:integer;  n:byte;
begin
for i:=1 to 51 do  if pos(zar[i],s)<>0 then begin
 n:=pos(zar[i],s);
 s[n]:= upcase(s[n]);
end;
progwork:=s;
end;

var
f,f1:text; s:string;
begin
zar[1]:='and'; zar[2]:='asm';zar[3]:= 'array';zar[4]:= 'begin';zar[5]:= 'case';
zar[6]:= 'const';zar[7]:= 'constructor';zar[8]:= 'destructor';zar[9]:= 'div';zar[10]:= 'do';
zar[11]:= 'downto';zar[12]:= 'else';zar[13]:= 'end';zar[14]:= 'exports';zar[15]:= 'file';
zar[16]:= 'for';zar[17]:= 'function';zar[18]:= 'goto';zar[19]:= 'if';zar[20]:= 'implementation';
zar[21]:= 'in';zar[22]:= 'inherited';zar[23]:= 'inline';zar[24]:= 'interface';
zar[25]:= 'label';zar[26]:= 'library';zar[27]:= 'mod';zar[28]:= 'nil';zar[29]:= 'not';
zar[30]:= 'object';zar[31]:= 'of';zar[32]:= 'or';zar[33]:= 'packed';zar[34]:= 'procedure';
zar[35]:= 'program';zar[36]:= 'record';zar[37]:= 'repeat';zar[38]:= 'set';zar[39]:= 'shl';
zar[40]:= 'shr';zar[41]:= 'string';zar[42]:= 'then';zar[43]:= 'to';zar[44]:= 'type';zar[45]:= 'unit';
zar[46]:= 'until';zar[47]:= 'uses';zar[48]:= 'var';zar[49]:= 'while';zar[50]:= 'with';zar[51]:= 'xor';
readln(s);
assign(f,s);
assign(f1,'D:\temp1.pas');
{$i-}reset(f);{$i+}
If IOresult<>0 then begin writeln('error'); readln; halt; end;
rewrite(f1);
repeat
 readln(f,s);
 writeln(f1,progwork(s));
until eof(f);
close(F); close(f1);
end.

volvo
Цитата(Oleg_Z @ 12.04.05 14:54)
прога во всех зарез. словах первую букуву делает большой.

:no: "Во всех зарезервированных словах, записанных только маленькими буквами". А если "FUNCTION a: integer", то что будет с FUNCTION ?

P.S. Вроде типизированные константы еще не отменили ... unsure.gif
Jaxx
Между прочим, OlegZ, твоя программа работает неправильно. Проверь сам. Ты пропустил проверку зарезервированных слов. То есть, после твоей проги из слова begin получается слово begIn и т.д. Нужно проверить, стоит ли слово отдельно, какие символы и знаки препинания стоят перед ним и после него.
Точнее, после знаков препинания все работает замечательно, а вот если зарезервированное слово входит в состав другого слова - blink.gif
volvo
Цитата(Jaxx @ 12.04.05 16:27)
после знаков препинания все работает замечательно, а вот если зарезервированное слово входит в состав другого слова -  blink.gif

Oleg_Z, вот и ответ на твой вопрос:
Цитата(Olez_Z @ 12.04.05 14:54)
А зачем разбивать на слова?
Jaxx
Вот в этом то и моя проблема. Как проверить, является ли слово действительно зарезервированным. Каким образом проверить символ, идущий перед этим словом и после него?
volvo
Ты меня понимать не хочешь? Я же тебе привел ссылку на рабочий код, который корректно определяет зарезервированные слова, что еще нужно?

Что-то по-моему, тема становится переливанием из пустого в порожнее... Я решение предлагаю - следует вопрос, "а как же это реализовать?"... Я еще раз повторяю - опять "В этом моя проблема".
volvo
Кстати, если функцию progwork, написанную Oleg_Z чуть-чуть подредактировать, то она будет работать гораздо более корректно:
function is_letter(ch: char): boolean;
begin
 is_letter := ch in ['a'..'z', 'A'..'Z', '_'];
end;
function progwork(s:string):string;
var
 i:integer;
 prev_n, n:byte;
 before, after: integer;
begin
 for i:=1 to 51 do begin
   prev_n := 0;
   repeat

     n := pos(zar[i], s);
     if prev_n = n then break;
     before := n - 1;
     after := n + length(zar[i]);

     if n <> 0 then begin
       if ( (before >= 1) and is_letter(s[before]) ) or
          ( (after <= length(s)) and is_letter(s[after]) ) then
       else s[n]:= upcase(s[n]);
     end;
     prev_n := n

   until n = 0;
 end;

 progwork:=s;
end;
Altair
Ну раскритиковали smile.gif
Я шаблон для рассуждений дал smile.gif
такие элементы как BegIn легко устраняются путем изменения кода. (проверять на вхождениеодного словав другое).
Так что разбивать на слова необязательно smile.gif

Цитата
Во всех зарезервированных словах, записанных только маленькими буквами". А если "FUNCTION a: integer", то что будет с FUNCTION ?

Ну для этого добавить в программуфункцию:

Код
Function UpStr(S:String):String; {перевод строки в верхний регистр}
Var I:Byte;
Begin
For I:=1 To ORD(S[0]) Do
Begin
 Case S[I] Of
  'a'..'z':S[I]:=Chr(Ord(S[I])-$20);
  'а'..'п':S[I]:=Chr(Ord(S[I])-$20);
  'р'..'я':S[I]:=Chr(Ord(S[I])-$50)
 End
End;
UpStr:=S
End;

И вот эти строчки:
Код
for i:=1 to 51 do  if pos(zar[i],s)<>0 then begin
n:=pos(zar[i],s);
s[n]:= upcase(s[n]);

Заменитиь на:
Код
for i:=1 to 51 do  if pos(UpStr(zar[i]),ipstr(s))<>0 then begin
n:=pos(Upstr(zar[i]),upstr(s));
s[n]:= upcase(s[n]);

smile.gif
Хотя возникает вопрос -если уже в большом регистре слово, зачем первую букву поднимать? smile.gif
Jaxx
А в моём варианте проги, кроме заполнения массива есть ещё какие-нибудь ошибки? Если да, то покажите... :p2:
volvo
blink.gif А ты проверь, работает она, или нет.
Если работает, то нет ошибок. Или ты думаешь мы как-то по другому будем определять ее корректность?
Jaxx
Цитата(volvo @ 13.04.05 16:11)
blink.gif А ты проверь, работает она, или нет.
Если работает, то нет ошибок. Или ты думаешь мы как-то по другому будем определять ее корректность?

Я и так знаю, что она не работает. unsure.gif И вообще. Меня на работе загрузили немного более серьезным языком программирования (RLL называется). Забот полон рот, как говорится. А тут ещё учёба со своим Паскалем. Ну не понимаю я его, и все!!! :fire:
Jaxx
А почему не пашет такой вариант:
Код

Uses CRT;
var
znak:array[1..8] of string;
slovo:array[1..51] of string[15];
kolvo:array[1..51] of byte;
kol:byte;
ch:char;
i,n:integer;
t:integer;
s,s1:string;
f:text;
begin
clrscr;
write('Vvedite imya redaktiruemogo faila: ');
readln(s);
assign(f,s);
reset(f);
{$I-}if ioresult<>0 then begin
     write('Oshibka chteniya faila!');
     halt(1); end;
{$I+}
s:=''; s1:=''; kol:=0;
slovo[1]:='and';slovo[2]:='asm';slovo[3]:='array';slovo[4]:='begin';slovo[5]:='case';
slovo[6]:='const';slovo[7]:='constructor';slovo[8]:='destructor';slovo[9]:='div';slovo[10]:='do';
slovo[11]:='downto';slovo[12]:='else';slovo[13]:='end';slovo[14]:='exports';slovo[15]:='file';
slovo[16]:='for';slovo[17]:='function';slovo[18]:='goto';slovo[19]:='if';slovo[20]:='implementation';
slovo[21]:='in';slovo[22]:='inherited';slovo[23]:='inline';slovo[24]:='interface';
slovo[25]:='label';slovo[26]:='library';slovo[27]:='mod';slovo[28]:='nil';slovo[29]:='not';
slovo[30]:='object';slovo[31]:='of';slovo[32]:='or';slovo[33]:='packed';slovo[34]:='procedure';
slovo[35]:='program';slovo[36]:='record';slovo[37]:='repeat';slovo[38]:='set';slovo[39]:='shl';
slovo[40]:='shr';slovo[41]:='string';slovo[42]:='then';slovo[43]:='to';slovo[44]:='type';slovo[45]:='unit';
slovo[46]:='until';slovo[47]:='uses';slovo[48]:='var';slovo[49]:='while';slovo[50]:='with';slovo[51]:='xor';
i:=0;
znak[1]:=' ';znak[2]:='.';znak[3]:=',';znak[4]:=';';znak[5]:=':';
znak[6]:='(';znak[7]:=')';znak[8]:='=';
for i:=1 to 51 do
    kolvo[i]:=kol;
while not seekeof(f) do begin
    readln(f,s);
    n:=length(s);
    t:=n-(n+1);
    if s=slovo[i] then begin
       if (s[t]=znak[i]) and (s[n+1]=znak[i]) then
          kolvo[i]:=kol+1;
    end;
    end;
    s1:='';
    s:='';
    for i:=1 to 51 do begin
       if kolvo[i]>0 then begin
          writeln('Slovo ',slovo[i],' vstrechaetsia ',kolvo[i],' raz');
    end;
 end;
readln;
close(f);
close(f1);
end.
volvo
Возьмем вот эти 2 цикла:
 for i:=1 to 51 do
   kolvo[i]:=kol;

{ СТОП !!! Дальше можешь не ходить }
{ Значение i после выхода из цикла НЕ ОПРЕДЕЛЕНО }

while not seekeof(f) do begin
   readln(f,s);
   n:=length(s);
   t:=n-(n+1);
   if s=slovo[i] then begin
      if (s[t]=znak[i]) and (s[n+1]=znak[i]) then
         kolvo[i]:=kol+1;
   end;
   end;
   s1:='';
   s:='';
   for i:=1 to 51 do begin
      if kolvo[i]>0 then begin
         writeln('Slovo ',slovo[i],' vstrechaetsia ',kolvo[i],' raz');
   end;
end;
Может, в "немного более серьезном языке программирования (который RLL называется)" это и не так, но в Паскале ИМЕННО так... angry.gif И никак иначе...
Jaxx
А вот так:

uses crt;
const
znak:array[1..14] of byte=(9,10,13,32,40,41,44,46,47,58,59,92,123,125);
var
slovo:array[1..51] of string[15];
{mass:array[1..51] of string;}
mask:array[1..51] of byte;
txt:array[1..60000] of char;
kol:byte;
ns:byte;
f1:text;
f:file of char;
simv:char;
flag:boolean;
j:byte;
n:byte;
dtxt:word;
i:word;
s,s1,temp:string;
begin
clrscr;
write('Vvedite ymia ishodnogo faila: ');
readln(s);
assign(f,s);
{$I-} reset(f); {$I+}
 if ioresult<>0 then begin
    writeln('file not found or read error!');
    readkey;
    close(f);
    halt(1);
 end;
i:=1;
for i:=1 to 51 do mask[i]:=0;
i:=1;
slovo[1]:='and';slovo[2]:='asm';slovo[3]:='array';slovo[4]:='begin';slovo[5]:='case';
slovo[6]:='const';slovo[7]:='constructor';slovo[8]:='destructor';slovo[9]:='div';slovo[10]:='do';
slovo[11]:='downto';slovo[12]:='else';slovo[13]:='end';slovo[14]:='exports';slovo[15]:='file';
slovo[16]:='for';slovo[17]:='function';slovo[18]:='goto';slovo[19]:='if';slovo[20]:='implementation';
slovo[21]:='in';slovo[22]:='inherited';slovo[23]:='inline';slovo[24]:='interface';slovo[25]:='label';
slovo[26]:='library';slovo[27]:='mod';slovo[28]:='nil';slovo[29]:='not';slovo[30]:='object';
slovo[31]:='of';slovo[32]:='or';slovo[33]:='packed';slovo[34]:='procedure';slovo[35]:='program';
slovo[36]:='record';slovo[37]:='repeat';slovo[38]:='set';slovo[39]:='shl';slovo[40]:='shr';
slovo[41]:='string';slovo[42]:='then';slovo[43]:='to';slovo[44]:='type';slovo[45]:='unit';
slovo[46]:='until';slovo[47]:='uses';slovo[48]:='var';slovo[49]:='while';slovo[50]:='with';slovo[51]:='xor';
 write('Vvedite imia novogo faila: ');
 readln(s1);
 assign(f1,s1);
 {$I-} rewrite(f1); {$I+}
  if ioresult<>0 then begin
     writeln('error writing file!');
     readkey;
     close(f1);
     halt(1);
  end;
  s:=''; s1:=''; temp:='';
  kol:=0;
  n:=0;
while not eof(f) do begin
  read(f,simv);
  inc(dtxt);
  ns:=ord(simv);
  txt[dtxt]:=chr(ns);
   for i:=1 to dtxt do begin
       ns:=ord(txt[i]);
       flag:=true;
       for j:=1 to 14 do begin
       if ns=znak[j] then flag:=false;
         if flag then s:=s+txt[i];
        for n:=1 to 51 do begin
          if s=slovo[n] then begin
            mask[n]:=kol+1;
            i:=1;
            for i:=1 to 51 do begin
              n:=i;
              if mask[n]>0 then begin
               write('Slovo : ' ,slovo[n]);
               writeln('vstrechaetsia : ',mask[n],' raz');
               s1:=slovo[n];
               writeln(f1,s1);
              end;
             end;
           end;end;end;end;end; {<== ЗДЕСЬ ПРОГРАММА ОСТАНАВЛИВАЕТСЯ НАМЕРТВО, ВЫХОЖУ ctrl+break}
readln;
close(f);
close(f1);
end.


sad.gif
volvo
А здесь - я прогнал пошагово... Посмотри внимательно, что происходит вот тут:

...
 for j:=1 to 14 do begin
   if ns=znak[j] then flag:=false;
   if flag then s:=s+txt[i]; { <-- следующий символ из файла НЕ читается... }
...

Я взял файл с первым словом 'const', но после 5-ой итерации получил в строке s значение "ссссс", т.е. просто дублирование первого символа. Это будет продолжаться бесконечно... Да и вложенных циклов достаточно много - даже если исправишь этот недочет, программа будет медленно работать...

А чего ты не хочешь воспользоваться функцией, которую я приводил в посте №17 (немного переделанная функция Oleg_Z)? Я ее вроде погонял, сбоев не нашел... Нормально работает...
Jaxx
Цитата(volvo @ 19.04.05 14:57)
А чего ты не хочешь воспользоваться функцией, которую я приводил в посте №17 (немного переделанная функция Oleg_Z)? Я ее вроде погонял, сбоев не нашел... Нормально работает...

Да я бы взял, но хочется понять, где я допускаю ошибки, чоб знать на будущее. Ошибки-то глупейшие! А из-за них курсач стоит на месте...
Romtek
Не сочтите за оффтоп, но есть готовые программы форматирования исходников Паскаля, одна их них - PTOP - Free Pascal source formatter - входит в дистриб компилятора FreePascal, её описание здесь: http://www.freepascal.org/tools/ptop.html
Цитата
ptop is a configurable source formatter. It pretty-prints your pascal code, much like indent does for C code.


Кстати, и исходники её доступны...
Jaxx
Цитата(Romtek @ 19.04.05 21:09)
Не сочтите за оффтоп, но есть готовые программы форматирования исходников Паскаля, одна их них - PTOP - Free Pascal source formatter - входит в дистриб компилятора FreePascal, её описание здесь: http://www.freepascal.org/tools/ptop.html
Кстати, и исходники её доступны...

Вот только с примерами всего-то 40 Мб :p2:
Romtek
Вот исходник и ЕХЕ вместе.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.