+-----------------------------------------------------------------------------------------------------------------------------------------------[CP #1]----+
|
|
|
|
|
|
|
  _|_| _|_|         _|  _|     _|
_|     _|  _|     _|_|_|_|_| _|_|
_| ODE _|_|         _|  _|     _|
_|     _| UMP     _|_|_|_|_|   _|
    _|_| _|           _|  _|   _|_|_|
|
|
|
|
|
|
|
+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
+--------------------------------------[1x05 Подрастающему поколению (/home/programming)]--------------------------------------+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

Статья написана для людей которые программируют
изредка. Для души так сказать.


Одна из относительно старых моих наработок в программирование. Программа выводящая свой исходник. Некоторые считают, что такую написать нельзя. Я знаю по крайней мере два способа. Первый - мой, который приведён здесь. Есть ещё один способ - он более подробно описан в moon_bug в 6 или 7 номере.

Тема: Написание программы выводящей свой исходный текст.
Собственно статья ниже.
Автор: p0st[[email protected]]

1. Введение.
2. Алгоритм работы программы.
3. Собственно написание.
4. Напоследок.
5. Прикрёплен мой листинг.


Введение:
Иногда нужно написать программу, выводящую свой листинг. Часто такие (или похожие) задачи бывают на различных конкурсах, соревнованиях и т.д. Часто встречая такие задачи в различных задачниках по программированию (в учебниках по нему же они встречаются, что-то заметно реже :)). Бывает не сразу понятно как подступиться к такой задаче. Я расскажу алгоритм, по которому можно самому написать программу выводящую свой листинг. Пример для Turbo Pascal 7.0 (delphi должен открыть как консольное приложение и всё будет работать). Вывод осуществляется в стандартный поток output.

Алгоритм работы программы:
Будем использовать следующий метод: в программе объявлена константа как массив типа string. В нём будет храниться код программы. Тогда нам для вывода исходника потребуется вывести константу и потом сделать тоже самое ещё раз. При выводе константы будут небольшие трудности, но с ними легко справиться по ходу написания.

Собственно написание:
Сначала примерный текст того, что должно быть(потом доредактируем по написанию, исправим ошибки какие будут. Сейчас главное накидать основу):
--------------------------------Start---------------------------------
program outsource;
const
   N=15;{Примерное количество строчек. потом исправим на какое надо}
   mas:array[-3..N]of string=(
   'program outsource;',{Массив объёвлен с отрицательными индексирование для 
                              более удобного использования по тексту}
   'const',
   'N=15;',
   'mas:array[-1..N]of string=(',
   {Здесь будут ещё строки всего пока N+4 строк, можно пока встывить пустышки.
    Мне лень.}
   );

var
   i:integer;

begin
   for i:=-3 to 0 do    {Выводим то что перед константой}
      writeln(mas[i]);

   for i:=-3 to N do
      writeln(#39,mas[i],#39,#44);
   {Выводим саму константу, кавычки при выводе использовать не рекоменуеться
     так как будут проблемы для вывода формирования того же в константе}

   writeln(#39,mas[N],#39);{Вывод последней строки константы без запятой}
   writeln(#41,#59);{Конец константы}

   for i:=1 to N-1 do      {Выводим сам текст программы}
      writeln(mas[i]);
   writeln(mas[N],#46);    {И end с точкой в конце}
end.
--------------------------------End-----------------------------------
Далее требуется перенести весь получившийся исходник в константу. Получившаяся константа должна иметь вид примерно следующий:
--------------------------------Start---------------------------------
mas:array[-3..N]of string=(
   'program outsource;',
   'const',
   'N=13;',
   'mas:array[-3..N]of string=(',
   'var',
   'i:integer;',
   'begin',
   'for i:=-3 to 0 do',
   'writeln(mas[i]);',
   'for i:=-3 to N-1 do',
   'writeln(#39,mas[i],#39,#44);',
   'writeln(#39,mas[N],#39);',
   'writeln(#41,#59);',
   'for i:=1 to N-1 do',
   'writeln(mas[i]);',
   'writeln(mas[N],#46);',
   'end'
);
--------------------------------End-----------------------------------
Теперь объединяем куски в одну программы. Проверяем ,чтобы в константе было нужное число строчек и всё в таком духе.
Проверяем(1.pas - наша программа, запускать из каталога, в котором tpc):
tpc.exe 1.pas
1.exe > 2.pas 
tpc.exe 2.pas
2.exe > 3.pas 
fc 2.pas 3.pas

Напоследок:
Если получаем что ошибок не найдено то всё хорошо, иначе смотрим получившийся исходник, находим разницу и правим по месту. Идея решения была объяснена в самом начале статьи. Сравнивать вывод программы надо не с первоначальным исходником (в котором могут быть комментарии и другие вещи для понимания решения) , а с тем что получиться в конечном итоге.
p.s. Для заинтересовавшихся - можно попробовать вывод в файл. Создаёт небольшие проблемы, но помогает лучше разобраться в принципе работы программы.
p.p.s. Используя этот же алгоритм мы можем написать программу выводящую свой листинг на любом (ну почти на любом) языке программирования. У меня есть реализация на ассемблере :).
Приложение 1.pas(с моими коментариями):
(*--------------------------Start-----------------------------------*) 
program outsource;
const
   N=13;{Количество строчек в константе.}
   mas:array[-3..N]of string=(
      'program outsource;',{Массив объёвлен с отрицательными индексирование 
                           для более удобного использования по тексту}
      'const',
         'N=13;',
         'mas:array[-3..N]of string=(',
         'var',
            'i:integer;',
         'begin',
            'for i:=-3 to 0 do',
               'writeln(mas[i]);',
            'for i:=-3 to N-1 do',
               'writeln(#39,mas[i],#39,#44);',
            'writeln(#39,mas[N],#39);',
            'writeln(#41,#59);',
            'for i:=1 to N-1 do',
            'writeln(mas[i]);',
            'writeln(mas[N],#46);',
         'end'
   );

var
   i:integer;

begin
   for i:=-3 to 0 do    {Выводим то что перед константой}
      writeln(mas[i]);

   for i:=-3 to N-1 do  
      writeln(#39,mas[i],#39,#44);
   {Выводим саму константу, кавычки при выводе использовать не рекоменуеться
      так как будут проблемы для вывода формирования того же в константе
      #39 - кавычка "'" #44 - запятая ","}

   writeln(#39,mas[N],#39);{Вывод последней строки константы без запятой}
   writeln(#41,#59);       {Конец константы #41 - скобка ")", #59 - ";"}

   for i:=1 to N-1 do      {Выводим сам текст программы}
      writeln(mas[i]);
   writeln(mas[N],#46);    {И "end" с точкой в конце  }
end.
(*--------------------------End-------------------------------------*)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+-----[content]-----------------------------------------------------------------------------------------------------------------------------(c)-CP--------+