Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Интерпритатор языка или что-то в этом роде. [D5, D6, D7]


Страницы:   1 2 3 4 5

S0N1K ©   (2004-10-08 21:00:00) 

Как бы объяснить то, что я хочу сделать?... Надо сделать интерпритатор нес-ких стандартных команд(такой маленький язык).
Пишем (на русском) текст, а прога берёт из него команды и т.п.
и выполняет.
Например пишем:
объект перемещение на 2 вверх
объект перемещение на 3 влево
объект перемещение на 2 вправо
А в рез-те на клеточном поле показано куда переместился наш объект.
При этом могут быть и циклы, условия...
Если меня кто-то понял, то подскажите с какой стороны подступиться к решению.


VMcL   (2004-10-10 17:37:00) [61]

>> programania ©  (10.10.04 03:40) [18]

http://www.delphimaster.ru/cgi-bin/forum.pl?id=1090676641&n=3
Особенное внимание, в частности, обратить на пост №681.

>> ЮрийК ©  (10.10.04 17:29) [21]

Посмотри JCF (Jedi Code Format) - экперт для форматирования исходного кода Object Pascal, он с исходниками, AFAIR.

P.S. Анкету обнови.


Palladin   (2004-10-10 17:36:00) [62]

еще один серолицый...


ЮрийК   (2004-10-10 17:32:00) [63]

Ю. Зотову:
С помощью какой программы генерился код из набора БНФ правил?


ЮрийК   (2004-10-10 17:29:00) [64]

А вот мне нужен бы разборщик кода (или синтаксический анализатор) с Delphi (object pascal). Это примерно как в Delphi меню нажимаем "Syntax check", а в ответ получаем - есть ошибки или нет. Но мне это нужно не только для проверки правильности кода, но и для некоторой обработки/анализа самого разбираемого кода.
Не знает ли кто, где подобное можно найти, желательно чтобы не слишком навороченное типа компилятора, компилятора мне как раз и не нужно? Наверняка что-то подобное уже делалось. Но сложно найти просто поиском, столько всего ненужного выдаётся.


KSergey   (2004-10-10 16:05:00) [65]

> programania ©  

Уймись, дите неразумное. На кого батон крошишь?

PS
Эх, зря я это написал.. Юрий безусловно не нуждается в поддержке...

PPS
Юрий, можно стырить Ваш приведенный здесь код?


Юрий Зотов   (2004-10-10 15:41:00) [66]

> programania ©   (10.10.04 03:40) [18]

Похоже, ветка уйдет в "потрепаться". Ну да и ладно, свое дело она уже сделала, так что не страшно.

Ну что ж, приступим.

> Под программированием я понимаю получение полезной программы.

Сорри, демагогия. Просьба - пожалуйста, впредь постарайтесь избегать. Несерьезно.

> Под изучением программирования без получения полезной
> программы я понимаю лишь оправдание пребывания на работе


Такие вещи не делаются в рабочее время. Кто как, а я обычно использую для чтения время, которое провожу в дороге. Все равно оно зря пропадает.

> Мне это говорит о том что программой никто не пользуется
> даже автор

Около 30 контор, десятки рабочих мест в каждой. Думаю, человек 1000 наберется. Ежедневно, в течение 6 лет. И это только по одному проекту, а он не один. Что касается автора (точнее, авторов), то вся наша контора нашей же программой и пользуется. Глупо было бы покупать чужой продукт, имея собственный.

1. Достаточно?
2. Можете назвать количество Ваших юзеров?

> или он недоступен пользователю.

Почти все из этих 30 контор заключили договор о поддержке. Есть официальная служба поддержки, ее адрес, прекрасно известен всем юзерам. Так что все доступно, без проблем.

1. Достаточно?
2. Можете привести объем Вашей поддержки?

>>так что теперь эти расширения вводятся быстро и просто.
> похоже спихнули на кого-то свое творение.


1. Если я его "спихнул", то кто же, по-Вашему, эти расширения вносит? Пушкин, что ли?

2. См. выше о поддержке. Как видите, ничего никуда не "спихнуто".

3. Лично я вношу те расширения, которые требуют досконального знания механизмов программы, а другие расширения вносят другие люди в команде (только это не называется "спихнул", потому что команда одна). Именно такая цель и ставилась с самого начала и именно под это все и было с самого начала заточено. Поскольку забивать гвозди - это необходимая, большая и важная работа, но забивать их следует молотком, а не микроскопом.

4. Выбирайте выражения, вежливый Вы мой. Все старожилы этого форума Вам с чистой совестью подтвердят, что если я тоже начну язвить в Ваш адрес, то мало Вам не покажется. Так что давайте взаимно обойдемся без этого.

> Кстати, размер программы не связан с ее полезностью и
> я не говорил о большой программе

Что касается полезности - см. кол-во юзеров выше (кстати, оно растет, сейчас в проработке находится еще несколько новых договоров). Значит, полезность все же есть. Что касается размера - Вы говорили о СЛОЖНОЙ программе (см. [12]: "Похоже никогда не писали сложных программ..."). Размер исходного кода программы отчасти коррелирует с ее сложностью, поэтому я его и указал. Но могу сказать и непосредственно о сложности - она примерно на уровне 1С (включая собственный язык и визуальные средства для создания юзерами своих форм - некий встроенный аналог Delphi). Кстати, многие из наших юзеров, опробовав наш продукт в Demo-версии, перешли с 1С на него и говорят, что 1С отдыхает. Я воздержусь от столь категоричных заявлений, но все же это независимое мнение пользователей - а оно кое-чего стоит.

1. Достаточно?
2. Можете назвать свой продукт аналогичной сложности?

>>Напишите интерпретатор Паскаля.
> ведь это же почти механическая работа.


А что, уже писали, раз так заявляете?

> Например, гораздо интереснее интерпретатор с русского.
> Это я готов обсуждать и делать бесконечно.


Желаю Вам удачи и долгих лет жизни. Поскольку они понадобятся.

Если эта тема Вам интересна, могу предложить маленькую подзадачку - напишите процедуру, которая, не используя никаких словарей, а только анализируя слова, переносила бы их по СТРОГИМправилам русского языка (то есть - по слогам (а не просто по гласным), одну букву от корня и других частей слова не отрывать и т.д.). И добейтесь от нее правильной работы... ну, скажем, на 90% (поскольку меньше вряд ли будет полезно - Вы же сами говорите, что программа должна быть полезной).

>>а не слепленная кое-как глючная поделка.
> А это даст только тщательная и кропотливая отладка
> это большой монотонный труд и никакая теория тут не
> поможет.


Похоже, Вы не видите разницы между отладкой программы и отладкой ее алгоритма. А ведь отладка программы- это ее доведение до точногосоответствия задуманному алгоритму, а отладка алгоритма- это уже переделкапрограммы (даже если в коде была изменена только одна запятая). Другой алгоритм - это уже другая программа.

Так вот - если с самого начала был задуман неверный алгоритм (а ведь для более-менее сложных задач никто не может дать гарантии, что он верен), то программуможно "тщательно и кропотливо" отладить до абсолютной безглючности (то есть, она будет абсолютно точно реализовывать задуманный алгоритм) - но эта абсолютно безглючная программа будет работать... неверно! Поскольку абсолютно точно реализует неверныйалгоритм. И никакой "большой монотонный труд" по отладке тут уже не поможет, поскольку программа и так уже абсолютно отлажена и становиться еще отлаженнее ей уже некуда.

И придется менять алгоритм. То есть, программу надо будет уже не отлаживать, а переделывать(или вообще переписывать заново). А ведь снова нет никакой гарантии, что и с новым алгоритмом не повторится та же самая история, и что не начнется бесконечная сказка под названием "У попа была собака". В итоге может получиться так, что на решение задачи будет потрачен действительно огромный труд, а вот каковы будут его результаты - это еще вопрос.

А вот теория как раз и гарантирует правильность алгоритма. На все 100%. И остается только его правильно реализовать. Так что, как видите, теория не просто помогает, а дает практически единственный надежныйспособ решения задачи. Причем в реально оцениваемыесроки, без использования рекурсивного метода "написал - переписал" (как Вы понимаете, сроки решения задачи таким методом предсказать невозможно).

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


А давайте не будем рассказывать друг другу букварь, ладно?

> и неизбежно придет к теория языков, парсинга и
> интерпретации, компиляции


Придет, это точно. Но еще лучше, если он придет к ним, не угробив сначала кучу времени на бессмысленный труд.

> если они действительно полезны,

Множество успешно работающих компиляторов Вас в полезности теории не убеждают? Или Вы полагаете, что их писали по Вашей методе - "на коленке"?

> а может и к чему-то своему лучшему,

Вы считаете, что можно изобрести алгебру, не зная арифметики?

И такой опыт и знания не дадут никакие книги и теории.

Опыт набивания шишек? Точно, такого опыта книги и теории не дадут. Потому что они рассказывают как раз о прямо противоположном - как НЕ набивать шишки.

===============

P.S.
По интерпретатору - позже. Сначала надо посмотреть и потестировать.


programania   (2004-10-10 03:40:00) [67]

>Юрий Зотов

>Если под программированием Вы подразумеваете кодинг, а изучение программирования к программированию не относите - то да, неделя будет без программирования. А если нет - то нет.
Под программированием я понимаю получение полезной программы.
Под изучением программирования без получения полезной программы
я понимаю лишь оправдание пребывания на работе

>Гы. Три раза. Миллион строк - это большая программа? Живет 6 лет.
>Мой кусок в ней (тоже немаленький) живет около 5 лет.
>И этот кусок поддержки практически не требует - Вам это о чем-нибудь говорит?
Мне это говорит о том что программой никто не пользуется даже автор
или он недоступен пользователю.

>так что теперь эти расширения вводятся быстро и просто.
похоже спихнули на кого-то свое творение.

Кстати, размер программы не связан с ее полезностью и
я не говорил о большойпрограмме

>Напишите интерпретатор Паскаля.
есть много более интересных вещей чем интерпретатор с Паскаля
ведь это же почти механическая работа.
Например, гораздо интереснее интерпретатор с русского.
Это я готов обсуждать и делать бесконечно.

>Вот именно. Нормально работающий результат,
>а не слепленная кое-как глючная поделка.
А это даст только тщательная и кропотливая отладка
это большой монотонный труд и никакая теория тут не поможет.

>А что касается публикаций, то ОЧЕНЬ много раз публиковались как раз БНФ,
>теория языков, парсинга и интерпретации/компиляции.
При реальном программировании, а не изучении, не только человек делает программу
но и программа делает человека т.е. глядя на то что получается
автор видит что можно упростить, обьеденить, сделать универсальным и т.п.
и неизбежно придет к теория языков, парсинга и интерпретации, компиляции
если они действительно полезны, а может и к чему-то своему лучшему,
И такой опыт и знания не дадут никакие книги и теории.

>Еще раз - не любой, а нормально работающий. ЛЮБОЙ - на фиг никому не нужен.
Так это очевидно

>Так я жду интерпретатор. Рабочий и написанный за час.
Вот за 50 минут можете не верить, причем большая часть времени пошла не на интерпретатор
Сделаете быстрее, тогда критикуйте но скажите
какую программу проще расширить или переделать эту в 35 строк или вашу в 500
Кстати я так и не понял откуда ваш интерпретатор берет команды
А вот у меня из текстового файла test.txt
Запишите туда примерно следующее:

объект перемещение на 2 вверх;
объект перемещение на 4 влево
объект перемещение на 2 вниз
объект перемещение на 4 вправо


program Project1;
uses Graphics, forms, SysUtils, windows, Classes;
var
r,h,w,x,y,dx,dy,z:integer;b:graphics.tBitmap;t:textFile;s:string;ce:tCanvas;
Procedure ss(n:string; var dy:integer; m:integer);
begin //Сообщения о действиях
dy:=m*StrToInt(trim(copy(s,pos(' на ',s)+4,2)));
ce.textOut(100,100,'Перемещение '+n+' на '+intToStr(m*dy)+'       ')end;
begin
h:=screen.height; w:=screen.width;  x:=w div 2; y:=h div 2; r:=h div 10;
ce:=tCanvas.create; ce.Handle:=GetDC(0);
b:=Graphics.tBitMap.create;b.width:=w; b.height:=h;
b.canvas.copyRect(rect(0,0,w,h),ce,rect(0,0,w,h));
assignFile(t,'test.txt');
reset(t);
ce.font.size:=18;ce.font.color:=$FF; ce.font.style:=[fsBold];
ce.Pen.color:=$ff;   ce.Pen.width:=4;
ce.fillRect(rect(x,y,x+r,y+r));
while not eof(t) do begin
 readln(t,s);
 ce.Draw(0,0,b);
 dx:=0; dy:=0;
 if pos('вверх',s)>0  then ss('вверх',dy,-1)  else
 if pos('вниз',s)>0   then ss('вниз',dy,+1)   else
 if pos('влево',s)>0  then ss('влево',dx,+1)  else
 if pos('вправо',s)>0 then ss('вправо',dx,-1) else
 if trim(s)<>'' then ce.textOut(0,0,'Неверная команда '+s+'       ');
 inc(x,dx*r);
 inc(y,dy*r);
 ce.rectangle(x-r,y-r,x+r,y+r);
 z:=GetTickCount+2000; while GetTickCount<z do application.processmessages;
end;
closeFile(t);
ce.Draw(0,0,b);
end.


Юрий Зотов   (2004-10-10 00:35:00) [68]

> programania ©   (09.10.04 14:51) [12]

> Неделя без программирования невыносима.

Если под программированием Вы подразумеваете кодинг, а изучение программирования к программированию не относите - то да, неделя будет без программирования. А если нет - то нет.

> Это способ получить результат максимально быстро:
> уже через час.


Не могли бы Вы подтвердить свои слова делом? То есть взять - и написать за час работающий интерпретатор команд, который хотя бы не будет спотыкаться на каждом шагу. И выложить его здесь.

А то какие-то уж очень голословные заявления получаются.

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


Гы. Три раза. Миллион строк - это большая программа? Живет 6 лет. Мой кусок в ней (тоже немаленький) живет около 5 лет. И этот кусок поддержки практически не требует - Вам это о чем-нибудь говорит?

> переделка неизбежна, лучше сразу об этом позаботиться и
> заложить эту возможность в программу, а не пытаться все
> предусмотреть,


Если Вы пишете (точнее, проектируете) так, что переделка неизбежна, то мне Вас жаль (кстати, это и есть результат упора в сторону кодинга, а не программирования). Не на переделку, а на расширение надо ориентироваться, без всяких переделок. И вот это как раз и есть закладывание в программу возможности "все предусмотреть". Именно поэтому тот самый мой кусок и не требует почти никакой поддержки - все возможности расширения в него были заложены заранее, так что теперь эти расширения вводятся быстро и просто. И так я делаю ВСЕГДА - что и Вам советую. Экономит массу времени и труда.

> А теория годится только для одурманивания заказчика и
> студентов.


Гы. Еще четыре раза. Напишите интерпретатор. Желательно не такой игрушечный, о котором тут говорится, а серьезный - например, с Паскаля. Вот тогда поговорим.

> А здесь человеку нужен результат.

Вот именно. Нормально работающий результат, а не слепленная кое-как глючная поделка. Потому что иначе это не тот результат, который хоть кому-нибудь нужен.

> Кстати, все это очевидные вещи и не раз публиковались

Очевидные для кого - для Вас? Для меня и очень многих других - неочевидные. А что касается публикаций, то ОЧЕНЬ много раз публиковались как раз БНФ, теория языков, парсинга и интерпретации/компиляции.

> Теорию у него никто бы не купил.

А он ее и не создавал. Давным-давно существует готовая.

> А бейсик был нужен любой и немедленно.

Еще раз - не любой, а нормально работающий. ЛЮБОЙ - на фиг никому не нужен.

P.S.
Так я жду интерпретатор. Рабочий и написанный за час.


Юрий Зотов   (2004-10-09 23:56:00) [69]

Окончание (файл DFM).


object CmdInterpreterForm: TCmdInterpreterForm
 Left = 333
 Top = 188
 Width = 719
 Height = 464
 Caption = 'Интерпретатор команд'
 Color = clBtnFace
 Font.Charset = DEFAULT_CHARSET
 Font.Color = clWindowText
 Font.Height = -13
 Font.Name = 'MS Sans Serif'
 Font.Style = []
 OldCreateOrder = False
 Position = poScreenCenter
 OnCreate = FormCreate
 OnDestroy = FormDestroy
 DesignSize = (
   711
   435)
 PixelsPerInch = 120
 TextHeight = 16
 object CmdEdit: TEdit
   Left = 8
   Top = 4
   Width = 587
   Height = 24
   Anchors = [akLeft, akTop, akRight]
   TabOrder = 0
 end
 object ExecButton: TButton
   Left = 605
   Top = 4
   Width = 100
   Height = 25
   Anchors = [akTop, akRight]
   Caption = 'Выполнить'
   Default = True
   TabOrder = 1
   OnClick = ExecButtonClick
 end
end


Юрий Зотов   (2004-10-09 23:55:00) [70]

Продолжение 2.


{ TObjectTable }

procedure TObjectTable.CheckIndex(Index: integer);
begin
 if (Index < 0) or (Index >= Count) then
   raise EListError.CreateFmt('Индекс элемента списка должен лежать в диапазоне 0..%d', [Count - 1])
end;

procedure TObjectTable.Clear;
var
 i: integer;
begin
 for i := Count - 1 downto 0 do
   DeleteObject(i)
end;

procedure TObjectTable.CreateObject(const AClassName: string; ALeft, ATop: integer);
var
 AClassID, NewObjectID, i: integer;
 S: string;
 DC: HDC;
 R: TRect;
begin
 AClassId := FindClassByName(AClassName);
 NewObjectID := 0;
 for i := 0 to Count - 1 do
   with Items[i]^ do
     if (ClassID = AClassID) and (ObjectID > NewObjectID) then
       NewObjectID := ObjectID;
 Inc(NewObjectID);
 SetLength(FObjectArray, Count + 1);
 FObjectArray[Count - 1] := nil;
 try
   New(FObjectArray[Count - 1]);
   with FObjectArray[Count - 1]^ do
   begin
     FillChar(ObjectRef, SizeOf(ObjectRef), 0);
     ClassID := AClassID;
     ObjectID := NewObjectID;
     ObjectRef := DelphiClassTable[ClassID].Create(nil);
     with TFriendControl(ObjectRef) do
     begin
       Parent := Application.MainForm;
       S := GetObjectName(AClassName, ObjectID);
       R := ClientRect;
       DC := GetDC(GetDesktopWindow);
       try
         R.Bottom := DrawText(DC, PChar(S), Length(S), R, DT_LEFT or DT_SINGLELINE or DT_CALCRECT)
       finally
         ReleaseDC(GetDesktopWindow, DC)
       end;
       SetBounds(ALeft, ATop, R.Right + 16, R.Bottom + 8);
       Text := S
     end
   end
 except
   DeleteObject(Count - 1);
   raise
 end
end;

procedure TObjectTable.DeleteObject(Index: integer);
begin
 CheckIndex(Index);
 if FObjectArray[Index] <> nil then
 begin
   with FObjectArray[Index]^ do
     if ObjectRef <> nil then
       ObjectRef.Free;
   Dispose(FObjectArray[Index])
 end;
 if Index < Count - 1 then
   Move(FObjectArray[Index + 1], FObjectArray[Index],
     (Count - Index - 1) * SizeOf(PObjectRecord));
 SetLength(FObjectArray, Count - 1)
end;

procedure TObjectTable.DeleteObject(const AClassName: string; AObjectID: integer);
begin
 DeleteObject(FindObject(AClassName, AObjectID))
end;

destructor TObjectTable.Destroy;
begin
 Clear;
 inherited
end;

function TObjectTable.FindObject(const AClassName: string; AObjectID: integer): integer;
var
 AClassID, i: integer;
begin
 AClassID := FindClassByName(AClassName);
 for i := 0 to Count - 1 do
   with Items[i]^ do
    if (AClassID = ClassID) and (AObjectID = ObjectID) then
    begin
      Result := i;
      Exit
    end;
 raise EStatementSyntaxError.CreateFmt('Неизвестный объект "%s"', [GetObjectName(AClassName, AObjectID)])
end;

function TObjectTable.GetCount: integer;
begin
 Result := Length(FObjectArray)
end;

function TObjectTable.GetItem(Index: integer): PObjectRecord;
begin
 CheckIndex(Index);
 Result := FObjectArray[Index]
end;

function TObjectTable.GetObject(const AClassName: string; AObjectID: integer): TControl;
begin
 Result := Items[FindObject(AClassName, AObjectID)]^.ObjectRef
end;

function TObjectTable.GetObjectName(const AClassName: string; AObjectID: integer): string;
begin
 Result := AClassName + IntToStr(AObjectID)
end;

{ TCmdInterpreterForm }

procedure TCmdInterpreterForm.FormCreate(Sender: TObject);
begin
 ObjectTable := TObjectTable.Create
end;

procedure TCmdInterpreterForm.ExecButtonClick(Sender: TObject);
begin
 ExecuteStatement(CmdEdit)
end;

procedure TCmdInterpreterForm.FormDestroy(Sender: TObject);
begin
 ObjectTable.Free
end;

end.


См. окончание.


Юрий Зотов   (2004-10-09 23:52:00) [71]

Продолжение 1.


type
 TCommandProc = procedure(const StrParam: string; const IntParams: TIntegerArray);
var
 CommandProcTable: array[tkMove..tkDelete] of pointer =
   (@MoveObjectProc, @CreateObjectProc, @DeleteObjectProc);

function FindString(const S: string; Table: TStringArray; Count: integer): integer;
var
 L, H, i, C: integer;
begin
 Result := -1;
 L := 0;
 H := Count - 1;
 while L <= H do
 begin
   i := (L + H) div 2;
   C := AnsiCompareText(Table[i], S);
   if C < 0 then
     L := i + 1
   else
     if C = 0 then
     begin
       Result := i;
       Exit
     end
     else
       H := i - 1
 end
end;

function FindClassByName(const AClassName: string): integer;
begin
 Result := FindString(AClassName, @ClassTable, ClassCount);
 if Result < 0 then
   raise EStatementSyntaxError.CreateFmt('Неизвестный класс "%s"', [AClassName])
end;

function FindCommand(const ACommand: string): integer;
begin
 Result := FindString(ACommand, @CommandTable, CommandCount);
 if Result < 0 then
   raise EStatementSyntaxError.CreateFmt('Неизвестная команда "%s"', [ACommand])
end;

procedure ExecuteStatement(Edit: Tedit);
const
 sInvalidChar = 'Недопустимый символ "%s"';
var
 Statement: string;
 CharPos: integer;
 Ch: char;
 Token: TToken;
 StrValue, TargetValue: string;
 CmdToken, TargetToken: TToken;
 IntValues: TIntegerArray;

 procedure NextChar(SkipSpaces: boolean = True);
 begin
   Inc(CharPos);
   if SkipSpaces then
     while (CharPos <= Length(Statement)) and (Statement[CharPos] = SpaceChar) do
       Inc(CharPos);
   if CharPos <= Length(Statement) then
   begin
     Ch := Statement[CharPos];
     if not (Ch in Alphabet) then
       if Ch < SpaceChar then
         raise EStatementSyntaxError.CreateFmt(sInvalidChar, ['#' + IntToStr(Byte(Ch))])
       else
         raise EStatementSyntaxError.CreateFmt(sInvalidChar, [Ch])
   end
   else
     Ch := EofChar
 end;

 function GetIdent: string;
 begin
   Result := '';
   while Ch in Letters do
   begin
     Result := Result + Ch;
     NextChar(False)
   end
 end;

 function GetUnsigned: Int64;
 begin
   Result := 0;
   while Ch in Digits do
   begin
     Result := Result * 10 + Byte(Ch) - Byte('0');
     NextChar(False)
   end
 end;

 procedure AddIntValue(const Value: Int64);
 begin
   SetLength(IntValues, Length(IntValues) + 1);
   IntValues[High(IntValues)] := Value
 end;

 procedure NextToken;
 var
   Negative: boolean;
 begin
   NextChar;
   if Ch <> EofChar then
   begin
     if Ch in Letters then
     begin
       StrValue := GetIdent;
       if Ch in Digits then
       begin
         AddIntValue(GetUnsigned);
         TargetValue := StrValue;
         TargetToken := tkObjectName;
         Token := TargetToken
       end
       else
         if Token = tkNone then
         begin
           CmdToken := CommandTokenTable[FindCommand(StrValue)];
           Token := CmdToken
         end
         else
           begin
             FindClassByName(StrValue);
             TargetValue := StrValue;
             TargetToken := tkClassName;
             Token := TargetToken
           end
     end
     else
       if Ch in Signs + Digits then
       begin
         if Ch in Signs then
         begin
           Negative := Ch = MinusChar;
           NextChar
         end
         else
           Negative := False;
         if Ch in Digits then
           if Negative then
             AddIntValue(-GetUnsigned)
           else
             AddIntValue(GetUnsigned)
         else
           raise EStatementSyntaxError.CreateFmt(sInvalidChar, [Ch]);
         Token := tkParam
       end
   end
   else
     Token := tkEoF
 end;

 procedure CheckCommand;
 begin
   if not ValidCommandTable[TargetToken, CmdToken] then
     raise EStatementSyntaxError.Create('Недопустимое сочетание объекта и команды')
 end;

 procedure CallCommandProc;
 begin
   TCommandProc(CommandProcTable[CmdToken])(TargetValue, IntValues)
 end;

begin
 Statement := Edit.Text;
 CharPos := 0;
 Token := tkNone;
 IntValues := nil;
 try
   try
     NextToken;
     if not (Token in [tkMove..tkDelete]) then
       raise EStatementSyntaxError.Create('Пропущена команда');
     NextToken;
     if not (Token in [tkClassName, tkObjectName]) then
       raise EStatementSyntaxError.Create('Пропущено имя класса или объекта');
     CheckCommand;
     repeat
       NextToken
     until Token <> tkParam;
     if Token <> tkEoF then
       raise EStatementSyntaxError.Create('Нераспознанная синтаксическая конструкция');
     CallCommandProc
   except
     with Edit do
     begin
       if Visible and Enabled then
         SetFocus;
       SelStart := CharPos - 1;
       SelLength := 1
     end;
     raise
   end
 finally
   IntValues := nil
 end
end;


См. продолжение 2.


Юрий Зотов   (2004-10-09 23:50:00) [72]

> S0N1K

Привожу обещанный пример. Интерпретатор умеет выполнять следующие команды:

1. создать имя_класса координата_X координата_Y
где имя_класса - это кнопка, метка, панель или редактор (пишется по-русски).
Созданному объекту назначается имя, состоящее из имени класса и порядкового номера. Объект появляется на форме в точке с заданными координатами. Его имя рисуется на нем самом.

2. переместить имя_объекта смещение_X смещение_Y
где имя_объекта - это имя любого из ранее созданных объектов.
Смещения задают точку перемещения относительно текущей и могут быть отрицательными.

3. удалить имя_объекта
где имя_объекта - это имя любого из ранее созданных объектов.

Код написан так, что набор команд расширяется без переделки алгоритма (вот для чего, в частности, нужна теория - но не только для этого). Все синтаксические и логические ошибки диагностируются. Код тестировался, но мало, поэтому ошибки не исключены.


unit Unit1;

interface

uses
 Windows, SysUtils, Classes, Controls, StdCtrls, ExtCtrls, Forms;

type
 TCmdInterpreterForm = class(TForm)
   CmdEdit: TEdit;
   ExecButton: TButton;
   procedure FormCreate(Sender: TObject);
   procedure ExecButtonClick(Sender: TObject);
   procedure FormDestroy(Sender: TObject);
 end;

var
 CmdInterpreterForm: TCmdInterpreterForm;

implementation

{$R *.dfm}

{**************************************************************}
{                                                              }
{ <statement> ::= <command> <target> <param_list>              }
{                                                              }
{ <command> ::= <identifier>                                   }
{ <target> ::= <class_name> | <object_name>                    }
{ <param_list> ::= <parameter> | <parameter> <param_list>      }
{                                                              }
{ <identifier> ::= <letter> | <letter> <identifier>            }
{ <class_name> ::= <identifier>                                }
{ <object_name> ::= <class_name> <unsigned>                    }
{ <parameter> := <empty> | <sign> <unsigned>                   }
{                                                              }
{ <letter> ::= A...y                                           }
{ <unsigned> := <digit> | <digit> <unsigned>                   }
{ <empty> ::=                                                  }
{ <sign> ::= <empty> | + | -                                   }
{                                                              }
{ <digit> ::= 0...9                                            }
{                                                              }
{**************************************************************}
{                                                              }
{ 1. <object_name> проверяется по таблице объектов ObjectTable }
{ 2. <class_name> проверяется по таблице классов ClassTable    }
{ 3. <command> проверяется по таблице команд CommandTable      }
{ 4. Алфавит нечувствителен к регистру                         }
{                                                              }
{**************************************************************}

type
 TToken = (tkNone, tkClassName, tkObjectName, tkMove, tkCreate, tkDelete, tkParam, tkEoF);

const
 Letters = ['А'..'я'];
 Digits = ['0'..'9'];
 MinusChar = '-';
 Signs = ['+', MinusChar];
 SpaceChar = ' ';
 EofChar = #0;
 Alphabet = Letters + Digits + Signs + [SpaceChar];

 ClassCount = 4;
 ClassTable: packed array[0..(ClassCount - 1)] of string =
   ('КНОПКА', 'МЕТКА', 'ПАНЕЛЬ', 'РЕДАКТОР'); // upper case, sorted
 DelphiClassTable: packed array[0..(ClassCount - 1)] of TControlClass =
   (TButton, TLabel, TPanel, TEdit);

 CommandCount = 3;
 CommandTable: packed array[0..(CommandCount - 1)] of string =
   ('ПЕРЕМЕСТИТЬ', 'СОЗДАТЬ', 'УДАЛИТЬ'); // upper case, sorted
 CommandTokenTable: packed array[0..(CommandCount - 1)] of TToken =
   (tkMove, tkCreate, tkDelete);
 ValidCommandTable: packed array[tkClassName..tkObjectName, tkMove..tkDelete] of boolean =
   ((False, True, False), (True, False, True));

type
 EStatementSyntaxError = class(Exception);
 TIntegerArray = packed array of Int64;
 TStringArray = packed array of string;
 TFriendControl = class(TControl);

 PObjectRecord = ^TObjectRecord;
 TObjectRecord = packed record
   ClassID: integer;   // индекс класса в ClassTable
   ObjectID: integer;  // числовой идентификатор объекта
   ObjectRef: TControl // ссылка на сам объект
 end;
 TObjectArray = packed array of PObjectRecord;

 TObjectTable = class(TObject)
 private
   FObjectArray: TObjectArray;
   function GetCount: integer;
   function GetItem(Index: integer): PObjectRecord;
 protected
   procedure CheckIndex(Index: integer);
   function GetObjectName(const AClassName: string; AObjectID: integer): string;
   function FindObject(const AClassName: string; AObjectID: integer): integer;
   procedure DeleteObject(Index: integer); overload;
   procedure Clear;
   property Count: integer read GetCount;
   property Items[Index: integer]: PObjectRecord read GetItem;
 public
   destructor Destroy; override;
   procedure CreateObject(const AClassName: string; ALeft, ATop: integer);
   function GetObject(const AClassName: string; AObjectID: integer): TControl;
   procedure DeleteObject(const AClassName: string; AObjectID: integer); overload;
 end;

var
 ObjectTable: TObjectTable;

procedure InvalidParamCount(ValidCount: integer);
begin
 raise EStatementSyntaxError.CreateFmt('Количество параметров должно быть равно %d', [ValidCount])
end;

procedure MoveObjectProc(const StrParam: string; const IntParams: TIntegerArray);
begin
 if Length(IntParams) <> 3 then
   InvalidParamCount(2);
 with ObjectTable.GetObject(StrParam, IntParams[0]) do
   SetBounds(Left + IntParams[1], Top + IntParams[2], Width, Height)
end;

procedure CreateObjectProc(const StrParam: string; const IntParams: TIntegerArray);
begin
 if Length(IntParams) <> 2 then
   InvalidParamCount(2);
 ObjectTable.CreateObject(StrParam, IntParams[0], IntParams[1])
end;

procedure DeleteObjectProc(const StrParam: string; const IntParams: TIntegerArray);
begin
 if Length(IntParams) <> 1 then
   InvalidParamCount(0);
 ObjectTable.DeleteObject(StrParam, IntParams[0])
end;


См. продолжение 1.


programania   (2004-10-09 14:51:00) [73]

>Юрий Зотов ©   (09.10.04 09:12) [10]
Недели достаточно.
Неделя без программирования невыносима.

> Лучше пишите сразу первое что придет в голову
>Это тоже способ, конечно. Но вот тогда как раз и есть хороший шанс получить "писать можно всю жизнь".
Это способ получить результат максимально быстро: уже через час.
А хорошую программу действительно можно писать всю жизнь и тогда она живет как человек.

> все равно всего сразу не предусмотрите
>Если писать без теории, то да. А если по теории, то нет.
>Потому что при таком подходе все переделывать действительно придется, и не один раз.
Похоже никогда не писали сложных программ и тем более не
сопровождали их годами, переделка неизбежна, лучше сразу об этом
позаботиться и заложить эту возможность в программу,
а не пытаться все предусмотреть,
все равно из того что предусмотрите большая часть окажется ненужной.
А теория годится только для одурманивания заказчика и студентов.
А здесь человеку нужен результат.
Кстати, все это очевидные вещи и не раз публиковались

> и не заметите как получите что-то типа бейсика
> похоже БГ так его и написал.
>Эт вряд ли.
Эт вряд ли.
Теорию у него никто бы не купил.
А бейсик был нужен любой и немедленно.


GanibalLector   (2004-10-09 11:35:00) [74]

2 Юрий Зотов ©
Вы даже меня заинтеровали с   Бэкуса-Наура.
Сейчас попробую накатать простенький пример, выложу здесь.
Жду с нетерпением.


Юрий Зотов   (2004-10-09 09:12:00) [75]

> programania ©   (09.10.04 01:54) [5]

> Разгребать можно всю жизнь
Недели достаточно.

> Лучше пишите сразу первое что придет в голову
Это тоже способ, конечно. Но вот тогда как раз и есть хороший шанс получить "писать можно всю жизнь".

> все равно всего сразу не предусмотрите
Если писать без теории, то да. А если по теории, то нет.

> не бойтесь все переделать
В этом совершенно согласен. Потому что при таком подходе все переделывать действительно придется, и не один раз.

> и не заметите как получите что-то типа бейсика
> похоже БГ так его и написал.
Эт вряд ли.
(с) тов. Сухов.

> GanibalLector ©   (09.10.04 02:17) [8]
Мало того, что пиво из рюмки, так ведь еще и пили эту рюмку аж целых 20 минут...
:о)

> S0N1K
Сейчас попробую накатать простенький пример, выложу здесь.


Германн   (2004-10-09 02:48:00) [76]

2 GanibalLector ©   (09.10.04 02:17) [8]
за рюмкой пива

Приезжай в Москву на встречу. Сразу все поймешь! И про пиво, и про рюмки, и про ЮЗ!


GanibalLector   (2004-10-09 02:17:00) [77]

за рюмкой пива
во дела!!!Люди начали пЫво пить из рюмок.Интелегенты что-ли???


Rouse_   (2004-10-09 02:13:00) [78]

Зы: Так что советую спросить у него хорошо, объяснять он умеет дай боже, преподаватель как никак ;)


Rouse_   (2004-10-09 02:11:00) [79]

> [4] S0N1K   (08.10.04 21:40)
Юрий стесняется по поводу (с какой стороны подступиться к решению), в свое время за рюмкой пива он объяснил мне все довольно популярно за минут 20, чему я кстати еще раз не могу не выразить ему "Вельми Респект"... :)


programania   (2004-10-09 01:54:00) [80]

>Нарыл кучу материала, теперь буду разгребать:)
Разгребать можно всю жизнь
Лучше пишите сразу первое что придет в голову
все равно всего сразу не предусмотрите
например:

s:='объект перемещение на 2 вверх';
if (pos('перемещение',s)>0)and(pos('вверх',s)>0) then
showmessage('надо вверх на '+copy(s,pos(' на ',s)+4,2));

и т.д.
похожие конструкции оформляйте в универсальные процедуры
для циклов, условий и переходов введите номер выполняемой строки
не бойтесь все переделать
и не заметите как получите что-то типа бейсика
похоже БГ так его и написал.


Страницы:   1 2 3 4 5

Наверх

Титульная страница Поиск, карта сайта Написать письмо