![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Интерпритатор языка или что-то в этом роде. [D5, D6, D7]
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));
и т.д.
похожие конструкции оформляйте в универсальные процедуры
для циклов, условий и переходов введите номер выполняемой строки
не бойтесь все переделать
и не заметите как получите что-то типа бейсика
похоже БГ так его и написал.