Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.01.05;
Скачать: [xml.tar.bz2];

Вниз

Парсер   Найти похожие ветки 

 
Alexious   (2003-12-17 23:34) [0]

Помогите написать простенький парсер


 
Sergey_Masloff   (2003-12-18 00:05) [1]

сама формулировка вопроса говорит о том, что помощь тут бесполезна...


 
Кщд   (2003-12-18 06:39) [2]

Sergey_Masloff (18.12.03 00:05) [1]
зачем же так грубо... :)

Alexious © (17.12.03 23:34)
вот, например:
program MegaParser;
var
a,b,s :string;
begin
s:="Простенький парсер";
a:=copy(s, 1, 11);
b:=copy(s, 13, 6);
end;
дарю
копирайт можешь не указывать


 
TUser   (2003-12-18 07:31) [3]

Лучше всего найти чей-то парсер и покопать исходники. И пробовать, пробовать, пробовать.


 
Юрий Зотов   (2003-12-18 08:26) [4]

> Alexious © (17.12.03 23:34)

А как бы Вы сами ответили на такой неконкретный вопрос? Ну, хорошо, положим кто-то захочет помочь - но чем конкретно он сможет помочь-то? Ничем. Потому что Вы не сообщили никакой информации.

Вы бы рассказали, что за парсер Вам нужен, какие конкретные проблемы у Вас возникли - вот это был бы уже деловой разговор.


 
Юрий Зотов   (2003-12-18 08:31) [5]

> TUser © (18.12.03 07:31) [3]

Если уж говорить о том, что лучше всего, то в ЭТОЙ задаче ЛУЧШЕ всего начать с чтения книг. Как минимум, нужно уметь построить формальное описание входного языка. Иначе никакие исходники не помогут - в грамотных не разберешься, а неграмотные лучше даже и не смотреть.


 
Alexious   (2003-12-18 17:23) [6]

>2All
Мне нужен парсер для програмного эмулятора процессора Intel Pentium MMX. Конкретно чтобы он мог понимать мнемокоманды и использовать нужные функции в соответствии с этими командами.


 
vuk   (2003-12-18 17:31) [7]

Нефигово...


 
Плохиш_   (2003-12-18 17:32) [8]

>Alexious © (18.12.03 17:23) [6]

> Мне нужен парсер для програмного эмулятора процессора Intel
> Pentium MMX

Простенкий, говоришь?

> Конкретно чтобы он мог понимать мнемокоманды и использовать
> нужные функции в соответствии с этими командами.

Это, что техзадание? Тогда сумма не указана :-(


 
Digitman   (2003-12-18 17:34) [9]

ты, вероятно, не представляешь в принципе ф-ции парсера

судя по [6] получается, что парсер у тебя должен заниматься СОВЕРШЕННО НЕСВОЙСТВЕННЫЕ парсерам ф-ции !

это - раз

второе : лексическим анализом будет Пушкин заниматься ?)


 
Digitman   (2003-12-18 17:38) [10]


> Alexious


мне показалось, что мало кому здесь стало понятно, ЧТО ты вообще парсить вознамерился


 
Alexious   (2003-12-18 17:59) [11]

А вот зачем
Я ввожу мнемокоманду MOV R1,R2
и у меня должна вызваться функция для того чтобы значению R1 приравнялось значение R2.
Таких команд много. (Всего R - 8 штук). И каждый можно приравнять к каждому. Вот зачем парсер.


 
Digitman   (2003-12-18 18:10) [12]


> Я ввожу мнемокоманду MOV R1,R2
> и у меня должна вызваться функция для того чтобы значению
> R1 приравнялось значение R2.
> Таких команд много. (Всего R - 8 штук). И каждый можно приравнять
> к каждому. Вот зачем парсер.


это не парсер, а целый кросс-ассемблер и/или интерпретатор

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

ищи в сети кросс-ассемблеры и интерпретаторы ассемблера для процессоров семейства DEC


 
Digitman   (2003-12-18 18:14) [13]

а парсер - лишь одна из составляющих таких систем

к тому же семантический/синтаксический парсинг осуществляется лишь после лексического парсинга, так что совершенно неясно , о каком конкретно парсинге ты говоришь и что из этих "кубиков" у тебя вызывает проблемы


 
Alexious   (2003-12-18 18:25) [14]

В том то и дело что мне нужна эта составляющая


 
Dimka Maslov   (2003-12-18 18:32) [15]

Если ты хочешь написать любой парсер, надо сесть у думать, думать, думать, потом написать и отладиживать, отлаживать, отлаживать. Потом купить книжку, прочитать её, на основе приобретённого опыта понять что сделал неправильно, переделать и парсер готов!


 
Maxim Vetera   (2003-12-18 18:34) [16]


> Alexious © (18.12.03 18:25)


Если будешь писать новый парсер - учти, что современный (конкурентноспособный) парсер должен уметь работать со строкой длиной в парсек.

У меня получаются такие строки, когда я 8-ой раз итерирую параметрическую L-систему.

Когда мне нужен был для нее парсер, я нашел его в инете. Если ты напишешь новый парсер, я рассмотрю вариант покупки его у тебя.


 
Тимохов   (2003-12-18 18:34) [17]

Dimka Maslov © (18.12.03 18:32) [15]
Это просто бог красноречия!!!
Сам неоднократно писал парсеры. К его словам могу добавить, что фразы надо повторять не по 3 раза, а где нить так раз по 10.


 
Digitman   (2003-12-18 18:36) [18]

зачем ? объясни вразумительно ?

тебе же нужно, чтобы мнемокод этот был в конечном итоге в том или ином виде исполнен ? ну так готовое ПО это с успехом и делает ! вернее - делают это интерпретаторы, а кросс-ассемблеры генерируют объектный машкод, который ты можешь с легкостью интерпретировать уже сам, безо всяких там парсеров, но пользую банальный case :

case KOp of
01:
case DstOperand of
01: ...
02: ...
03: ...

...
end;
case SrcOperand of
01: ...
02: ...
03: ...

...
end;
....
end;


 
Alexious   (2003-12-18 18:38) [19]

Напишите кто-нить пример парсера. простого. Что я и хотел сначала


 
Digitman   (2003-12-18 18:44) [20]


> Alexious


ну просто ослиное упрямство !))))

да не парсер тебе нужен для начала, а лексический анализатор текста ! Коль уж на то пошло) ..

Вот и спрашивай тогда, приведите, мол, фрагменты кода, осуществляющие лексический разбор такой-то набора языковых конструкций !

Лексер превращает исходный тект в набор лексем, распознанных и снабженных тэгами... и только после этого на сцену выступает парсер)


 
Digitman   (2003-12-18 18:46) [21]

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


 
Digitman   (2003-12-18 18:48) [22]

впрочем, если тебя так приспичило, скачивай в сети OpenSource-пакет TP Lex&Yacc - там ты найдешь то что тебе нужно, посмотришь, насколько все это нетривиально и плюнешь на свою бредовую затею)


 
Dimka Maslov   (2003-12-18 18:50) [23]

Не может быть простого примера. Ну не может.


 
Maxim Vetera   (2003-12-18 18:53) [24]


> Alexious ©


Интерпретатор математических выражений пойдет?


 
Dimka Maslov   (2003-12-18 18:58) [25]

И что он с ним делать будет? В таких вещах надо всё самому делать, а не на форумах вопросы задавать.


 
Maxim Vetera   (2003-12-18 19:01) [26]

Он от нас отвяжется.


 
Dimka Maslov   (2003-12-18 19:02) [27]

>Maxim Vetera © (18.12.03 19:01) [26]
Да неужели? Только больше приставать будет


 
Alexious   (2003-12-18 19:03) [28]

Мне все что угодно подойдет
Мне че грубо вырезать из строки символы чтоли?
Я вот что хочу есть процедура

procedure MOV(R1:byte,R2:byte);
begin
R2:=R1;
end;

тупо
мне нада писать в TEdit- "MOV(1,3)" и чтобы это воспринималось как вызов функции


 
Maxim Vetera   (2003-12-18 19:04) [29]

unit FuncParser;

interface

uses
Math, SysUtils;

const
Capacity = 100;

type
TOperation = Array [1..Capacity] of byte;
//код операции
TOperand = Array [1..2] of Word;
//операнды
TAoTOperand = Array [1..Capacity] of TOperand;
TAoSingle = Array [1..Capacity div 2] of Single;
//величины

TPFRecord = Record
rb: TAoTOperand;
ro: TOperation;
rc: TAoSingle;
Blength: word; //=fi
Clength: word; //=ci
End;
{needed for import/export}

TParsedFunction = class (TObject)

public
procedure ParseFunction(s: ShortString; var ErCode: byte);
function Compute(const x: single = 0;
const y: single = 0;
const z: single = 0): single;
procedure ExportParsed(var r: TPFRecord);
procedure ImportParsed(const r: TPFRecord);

private
a: TAoSingle ;
{ elementary blocks }
b: TAoTOperand;
{numbers of el. blocks, envolved in operation}
o: TOperation;
{ code of operation }
c: TAoSingle;
{ constants, maybe variables or numbers;
c[1]=x, c[2]=y, c[3]=z, c[4]=PI, c[5]=e, ....}

fi : word; //free index, also length of array b
ConstIndex : word; //last index for const, starting from 3

End; //class

implementation

procedure TParsedFunction.ImportParsed;
var i: word;
begin
for i:=1 to r.Blength do
begin
o[i]:=r.ro[i];
b[i]:=r.rb[i];
end;
for i:=4 to r.Clength do
c[i]:=r.rc[i];

ConstIndex:=r.Clength;
fi:=r.Blength;
end;

procedure TParsedFunction.ExportParsed;
var i: word;
begin
for i:=1 to fi do
begin
r.ro[i]:=o[i];
r.rb[i]:=b[i];
end;
for i:=4 to ConstIndex do
r.rc[i]:=c[i];

r.Clength:=ConstIndex;
r.Blength:=fi;

end;

Function TParsedFunction.Compute(const x,y,z:single):single;
var i: word;

begin
c[1]:=x;
c[2]:=y;
c[3]:=z;
c[4]:=PI;
c[5]:=exp(1);

for i:=fi downto 1 do
case o[i] of
0 : a[i]:= c[b[i,1]]; // Assignment
1 : a[i]:= a[b[i,1]] + a[b[i,2]]; // Summ
2 : a[i]:= a[b[i,1]] - a[b[i,2]]; // Substract
3 : a[i]:= a[b[i,1]] * a[b[i,2]]; // Multiplication
4 : a[i]:= a[b[i,1]] / a[b[i,2]]; // Division
5 : a[i]:= sqr(a[b[i,1]]); // ^2
6 : a[i]:= sqrt(a[b[i,1]]); // square root
7 : a[i]:= power(a[b[i,1]],a[b[i,2]]); // Power
8 : a[i]:= sin(a[b[i,1]]); // Sin
9 : a[i]:= cos(a[b[i,1]]); // Cos
10 : a[i]:= tan(a[b[i,1]]); // Tangence
11 : a[i]:= cot(a[b[i,1]]); // Cotangence
12 : a[i]:= exp(a[b[i,1]]); // exp
13 : a[i]:= ln(a[b[i,1]]); // ln
14 : a[i]:= -a[b[i,1]]; // unary -
//RESERVED for possible future use
16 : a[i]:= trunc(a[b[i,1]]); // whole part
17 : a[i]:= round(a[b[i,1]]); // round
18 : a[i]:= arcsin(a[b[i,1]]); // arcsin
19 : a[i]:= arccos(a[b[i,1]]); // arccos
20 : a[i]:= arctan(a[b[i,1]]); // arctan
21 : a[i]:= arccot(a[b[i,1]]); // arccotan
22 : a[i]:= sinh(a[b[i,1]]); // hyp sin
23 : a[i]:= cosh(a[b[i,1]]); // hyp cos
24 : a[i]:= tanh(a[b[i,1]]); // hyp tan
25 : a[i]:= coth(a[b[i,1]]); // hyp cotan
26 : a[i]:= abs(a[b[i,1]]); // abs. value

end; //case

Result:=a[1];
end; //proc

procedure TParsedFunction.ParseFunction;
const
letter : set of Char = ["a".."z", "A".."Z"];
digit : set of Char = ["0".."9"];
operand : set of Char = ["-","+","*","/","^"];
bracket : set of Char = ["(",")"];
variable : set of Char = ["x","y","z"];

var

i,j : word; //counters
len : word;
ls: string;

function MyPos(const ch: char; const start,fin:word):word;
{searches ch in s OUTSIDE brackets in given interval}

var i,br: integer;
begin
Result:=0;
br:= 0;
For i:=fin downto start do
begin
case s[i] of
"(" : inc(br);
")" : dec(br);
end;
if (br=0) and (ch=s[i]) then Result:=i;
end;

end;

procedure ReversePluses(const start,fin:word);
var i,br: integer;
ch: char;
begin
br:=0;
for i:=start to fin do
begin
case s[i] of
"(" : inc(br);
")" : dec(br);
end;
if br=0 then
begin
ch:=s[i];
if s[i]="+" then ch:="-";
if s[i]="-" then ch:="+";
s[i]:=ch;
end;
end;
end;

procedure ReverseDiv(const start,fin:word);
var i,br: integer;
ch: char;
begin
br:=0;
for i:=start to fin do
begin
case s[i] of
"(" : inc(br);
")" : dec(br);
end;
if br=0 then
begin
ch:=s[i];
if s[i]="/" then ch:="*";
if s[i]="*" then ch:="/";
s[i]:=ch;
end;
end;
end;

procedure ParseExpr(start,fin,curfi:word);
{index of a block is fi}

var
cp : word;//cur position
ss,st: string;
mynum : single;
i,br:word;
br_ok : boolean;
Err : integer;

begin

repeat

ss:= Copy(s,start,fin-start+1); //for debug

//first get rid of useless enclosing brackets if present
// like here: (sin(x)/cos(y))

If (s[start]="(") and (s[fin]=")") then
begin

//If we have any operator within brackets at which
//bracket counter (br) = 0, then we MUST NOT remove brackets
//If there is none, we CAN do that.

br_ok:=true; //we CAN remove by default
br:= 0;
for i:=start to fin do
Case s[i] of
"(" : inc(br);
")" : dec(br);
"+","-","*","^","/" :
if br=0 then br_ok:=false;
end;

if br_ok then
begin
inc(start);
dec(fin);
continue;
end;

end;

// seek for +
cp:= MyPos("+",start,fin);
If cp>0 then
begin
o[curfi]:=1;
fi:=fi+1;
b[curfi,1]:=fi;
ParseExpr(start,cp-1,fi);
fi:=fi+1;
b[curfi,2]:=fi;
ParseExpr(cp+1,fin,fi);
break;
end;


 
Maxim Vetera   (2003-12-18 19:06) [30]

//seek for -
cp:= MyPos("-",start,fin);
If cp>0 then
begin
If cp>start then
begin
o[curfi]:=2;
fi:=fi+1;
b[curfi,1]:=fi;
ParseExpr(start,cp-1,fi);
fi:=fi+1;
ReversePluses(cp+1,fin);
//change + for - and vice versa
b[curfi,2]:=fi;
ParseExpr(cp+1,fin,fi);
end
else
begin //unary -
o[curfi]:=14;
fi:=fi+1;
ReversePluses(1,fin);
b[curfi,1]:=fi;
ParseExpr(start+1,fin,fi);
end;
break;
end;

//seek for *
cp:= MyPos("*",start,fin);
if cp>0 then
begin
o[curfi]:=3;
fi:=fi+1;
b[curfi,1]:=fi;
ParseExpr(start,cp-1,fi);
fi:=fi+1;
b[curfi,2]:=fi;
ParseExpr(cp+1,fin,fi);
break;
end;

//seek for /
cp:= MyPos("/",start,fin);
If cp>0 then
begin
o[curfi]:=4;
fi:=fi+1;
b[curfi,1]:=fi;
ParseExpr(start,cp-1,fi);
fi:=fi+1;
b[curfi,2]:=fi;
ReverseDiv(cp+1,fin);
//change * for / and vice versa
ParseExpr(cp+1,fin,fi);
break;
end;

//seek for ^;
cp:= MyPos("^",start,fin);
if cp>0 then
begin
o[curfi]:=7;
fi:=fi+1;
b[curfi,1]:=fi;
ParseExpr(start,cp-1,fi);
fi:=fi+1;
b[curfi,2]:=fi;
ParseExpr(cp+1,fin,fi);
break;
end;

//seek for variables
If length(ss)=1 then
case UpCase(s[start]) of
"X" : begin
o[curfi]:=0;
b[curfi,1]:=1;
break;
end;
"Y" : begin
o[curfi]:=0;
b[curfi,1]:=2;
break;
end;
"Z" : begin
o[curfi]:=0;
b[curfi,1]:=3;
break;
end;
end; //case

If s[start] in digit then
begin
val(ss,mynum,Err);
If Err=0 then
begin
//ReadNumber(start, mynum);
o[curfi]:=0;
ConstIndex:=ConstIndex+1;
b[curfi,1]:=ConstIndex;
c[ConstIndex]:=mynum;
end
else ErCode:=4;
break;
end;

//we have either function either special char, e.g. PI
//check for PI
if UpperCase(ss)="PI" then
begin
o[curfi]:=0;
b[curfi,1]:=4;
break;
end;
//check for E
if UpperCase(ss)="E" then
begin
o[curfi]:=0;
b[curfi,1]:=5;
break;
end;

//seek for func, as we have nothing else possible
//we have a function. Every func must have arg in brackets
//So, read ss until opening bracket:
cp:= MyPos("(",start,fin);
if cp<>0 then
begin
st:= Copy(s,start,cp-start);
st:=UpperCase(st);

if st="SQR" then
begin
o[curfi]:=5;
fi:=fi+1;
b[curfi,1]:=fi;
ParseExpr(cp, fin,fi);
break;
end;

if st="SQRT" then
begin
o[curfi]:=6;
fi:=fi+1;
b[curfi,1]:=fi;
ParseExpr(cp, fin,fi);
break;
end;

if st="SIN" then
begin
o[curfi]:=8;
fi:=fi+1;
b[curfi,1]:=fi;
ParseExpr(cp, fin,fi);
break;
end;


...


if st="ABS" then
begin
o[curfi]:=26;
fi:=fi+1;
b[curfi,1]:=fi;
ParseExpr(cp, fin,fi);
break;
end;

end; //if

if ErCode<>4 then ErCode:=1;

until ErCode<>0;

end; //proc

begin

len:= length(s);
fi:= 1;
ConstIndex:= 5;

//Check for errors first
ErCode:=0;
j:=0;
for i:=1 to len do
begin
if s[i]="(" then inc(j);
if s[i]=")" then dec(j);
end;
if j<>0 then ErCode:=2;

if ErCode<>2 then
for i:=1 to len do
if not ((s[i] in digit) or (s[i] in letter) or (s[i] in operand)
or (s[i] in [")","(","."," "])) then ErCode:=3;

//kill all spaces

ls:="";
for i:=1 to len do
if s[i]<>" " then ls:=ls + Copy(s,i,1);

len:=length(ls);

//a bit of optimization: kill useless unary pluses

if ls[1]<>"+" then s:=s[1] else s:="";
for i:=2 to len do
if (ls[i]<>"+") or (ls[i-1]<>"(") then
s:=s + Copy(ls,i,1);

len:=length(s);

if ErCode=0 then ParseExpr(1,len,1);

end; //func

end.

{ (c) 2003 Щеглов Илья Александрович, студент факультета ФН
МГТУ им. Н.Э. Баумана, Москва }


 
Maxim Vetera   (2003-12-18 19:07) [31]

{Version 1.02}

{Юнит содержит класс TParsedFunction и описания типов, необходимых для
работы с ним.

Класс TParsedFunction (PF) является интерпретатором (парсером) функций.
Метод ParseFunction позволяет распознать любое математическое выражение,
содержащее (опционально) x, y, z, различные мат. функции и численные
константы (см. список ниже), записанное в виде строки. Распознанное выражение
записывается особым образом в виде 4 массивов переменных. При этом метод
содержит параметр ErCode, позволяющий определить, успешно ли прошла операция
распознавания:
ErCode =
0 - Операция прошла успешно
1 - Встречена неизвестная функция или оператор
2 - В выражении содержится неравное количество открывающихся и
закрывающихся скобок
3 - Обнаружен недопустимый символ
(допустимыми являются: лат буквы любого регистра, цифры, круглые
скобки, пробел, символы + - * / ^ и точка.)
4 - Вероятно, пропущен оператор ( ситуация типа 12х )

Метод Compute позволяет вычислить значение ранее распознанной функции для
заданных значений x, y и z (если параметр опущен, он считается равным 0).

Методы ImportParsed и ExportParsed позволяют импортировать/экспортировать
распознанные функции в види запаси типа TPFRecord.

Принцип и алгоритм работы парсера:
Рассмотрим следующее выражение (в качестве примера):

(5+у)*sin(x^3)+х

Это выражение можно записать как а1 = а2 + а3,
где а2 = (5+у)*sin(x^3), а а3 = х.
В свою очередь, а2 = а4*а5, где а4 = 5+у, а а5 = sin(х^3)...
И так далее. В конце концов мы получим цепочку простейших операций
над двумя или одним операндом, каждый из которых может быть либо
числом/переменной, либо другой парой операндов.
Цепочка технически записывается тремя массивами: одномерным массивом,
содержащим указание на операцию (в моем юните каждая операция обозначена
номером и хранится в типе byte - вряд ли вы придумаете более 255 операций :)
Я лично вспомнил только 23 :)). Второй массив является двухмерным и
хранит ссылки на участывующие в операции операнды. Ссылки представляют
собой номера звеньев цепи и хранятся в типе word.
Третий массив содержит переменные, числовые константы и числа, обнаруженные
в выражении. Этот массив связан двумя первыми операций присвоения, которая
у меня имеет номер 0. В этом случае номер первого операнда ссылается не на
элемент массива операндов, а на элемент этого тертьего массива.
Как видите, все просто!
Чтобы подсчитать значение выражения, необходимо ввести еще один массив
(у меня обозначен как а). Заметьте, что операнды, участвующие в каждой
операции, всегда имеют номер больше, чем у этого операнда. Поэтому, чтобы
вычислить значение самого выражения (т.е. элемента а1), достаточно
подсчитать значение каждого элемента а, начиная с конца массива.

Скорость вычисления:
Благодаря тому, что распознавание функции производится только 1 раз,
а вся операция вычисления по сути сводится к действиям над массивами,
удается достичь скорости вычисления, сравнимой со скоростью вычисления
того же выражения самим компилятором Дельфи.
Сами скорости вычисления различаются в зависимости от сложности выражения
(иногда скорость вычислений парсера получается даже выше, чем у компилятора!
Это вызвано определенной оптимизацие выражения при парсинге), но в среднем
время вычислений парсера составляет 150-200% времени вычислений компилятора.

Точность вычислений:
Информация хранится в типе Single. В большей точности нет смысла, псокольку
в строке действительные числа передаются с очевидной погрешностью. В любом
случае, чтобы добиться большей точности, необходимо просто поменять single на
нужный тип, везде, где он встречается.
Точность вычислений в среднем составляет е-5

Формат представления строки:
- Длина строки ограничена 255 символами
(ограничение можно снять, заменив shortString на ansiString в
определении метода)
- Регистр букв НЕВАЖЕН
- Разрешается использовать пробелы
- Десятичная часть должна быть отделена точкой (а не запятой)
- Выражение должно быть записано по обычным правилам записи мат. выражений
для компьютера. (Например: x^2 + sin(5*y)/exp(4*z) )
- Программа учитывает приоритет действий (в порядке убывания: вычисление
функций, взятие в степень, умножение и деление, сложение и вычитание)
- Программа учитывает скобки
- Программа знает следующие мат. операции:
+ : сложение
- : вычитание
/ : деление
* : умножение
^ : возведение в произвольную степень
- Программа знает следующие мат. функции:
sin - синус
cos - косинус
tan - тангенс
cot - котангенс
exp - экспонента
ln - нат. логарифм
sqr - квадрат
sqrt - квадратный корень
round - округление
trunc - целая часть
asin - арксинус
acos - арккосинус
atan - арктангенс
acot - арккотангенс
sinh - гип. синус
cosh - гип. косинус
tanh - гип. тангенс
coth - гип. котангенс

- Программа знает следующие числовые константы:
pi - число пи
e - число е

- Программа понимает функции вплоть до 3 переменных.
Переменные обозначаются буквами x, y, z

- Программа понимает только числа, представленные в
десятином виде

Примечание (емкость массивов)
Требуемая емкость массива определяется как сумма:
кол-во операторов(функций) + кол-во вхождений величин + 2.
Например: 5*sin(x^3)+х
4 оператора (умножение, синус, сложение, возведение в степень)
+
4 вхождения величин (5, 3, х, х)
+
2 = 10.
Автору представляется, что емкости 100 должно хватить для записи
весьма сложного выражения. В любом случае емкость можно увеличить
изменением константы Capacity.
(Изначально в программе использовались динамические массивы,
но затем от них пришлось отказаться - слишком много геммороя :) )

!WARNINGS!

Необходимо самостоятельно контролировать следующие вещи:
- Обращение к методу Compute для нераспознанной функции вызовет
ошибку времени исполнения
- Превышение возможной емкости массивов также, разумеется, вызовет ошибку.
Подгоните значение Capacity под собственные нужды.
- Ошибки типа деления на ноль, которые могут быть в выражении, лежат
полностью на совести пользователя

ЛИЦЕНЗИЯ:
Данный юнит и представленные в нем классы и методы, а также алгоритм
распознавания функций являются интеллектуальной собственностью
ЩЕГЛОВА ИЛЬИ АЛЕКСАНДРОВИЧА <franzy@comail.ru>.
Данные класс, его методы и алгоритм распространяются бесплатно для
некоммерческого использования. Какое-либо другое распространение
указанной информации с целью получения выгоды запрещено. Использование
класса, его методов или алгоритма распознавания в программах,
распространяемых комерческим путем, возможно только с письменного
разрешения названного выше владельца авторского права.

Данная информация должна быть указана в теле любой программы, использующей
алгоритм распознавания, класс или его методы.

Благодарности:
Юрию Лапухову за помощь в обнаружении ошибок в алгоритме

}


 
Dimka Maslov   (2003-12-18 19:15) [32]

На самом деле разработка парсера математических выражений и командного (языкового) парсера разные задачи и подходы к мероприятию тоже разные.


 
Юрий Зотов   (2003-12-18 21:33) [33]

Ну, мой пример парсера попроще и попонятнее будет. Специально написал самое примитивное, что только пришло в голову (но все же практически "по канонам"). Тестировал наскоро, поэтому полное отсутствие ошибок не гарантирую, да и не в этом была цель.

Парсер разбирает на лексемы и проверяет синтаксическую правильность предложения Declaration со следующим входным языком:

<Declaration> ::= var <Identifier>: integer;
<Identifier> ::= <Letter>
<Letter> <Identifier>
<Letter> ::= "a".."z", "A".."Z"

что соответствует Паскалевскому:
var идентификатор: integer;
Длина идентификатора не ограничена, но в нем допускаются только буквы. Пробелы и переводы строк игнорируются везде, кроме как внутри ключевых слов и идентификатора. Регистровой чувствительности нет.

На форму надо бросить Memo1 и Button1. В Memo вводим искомый текст, жмем на кнопку и срабатывает ее обработчик OnClick:

const
Letters = ["a".."z", "A".."Z"];
Colon = ":";
Semicolon = ";";
IgnoredChars = [ #9, #10, #13, #32];

type
TToken = (tkIdentifier, tkInteger, tkVar, tkColon, tkSemicolon);
TKeywordIndex = tkInteger..tkVar;

const
KeyWords: array [TKeyWordIndex] of string = ("INTEGER", "VAR");

procedure TForm1.Button1Click(Sender: TObject);
var
S: string; //


 
Кен   (2003-12-20 02:31) [34]


> Maxim Vetera © (18.12.03 19:04) [29]


Браво ! Классная штука !


 
Германн   (2003-12-20 03:01) [35]

Ну, господа. По-моему большинство из Вас не учли дату!
Кто-то, может быть, еще не знает, а кто-то уже забыл, что такое последние дни декабря.
Я имею в виду "лето красное пропела", а теперь "так поди же попляши".
Но тогда уж автору сабжа стоит объяснить и уточнить, что ему нужно!


 
TUser   (2003-12-20 11:36) [36]

Что-то не верится, что в природе еще не существует нормального парсера для АСМа. Так зачем его самому писать?


 
Юрий Зотов   (2003-12-20 11:47) [37]

> Германн © (20.12.03 03:01) [35]

В сказанном Вами контексте от приведенных примеров никакого толку "за просто так" все равно не будет. В них придется капитально разбираться, иначе первый же вопрос - и большой привет! А если человек разберется - то уже хорошо.


 
Германн   (2003-12-21 03:09) [38]

2 Юрий Зотов © (20.12.03 11:47) [37]
"В сказанном мною контексте" от приведенных примеров может быть толк! Но, только, и если, "вышеприведенные примеры", случайно, попали туда, куда нужно. А "если человек разберется - уже хорошо" - тут "сто пудов"!



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2004.01.05;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.6 MB
Время: 0.013 c
14-12093
Andrew_Glotov
2003-12-11 21:01
2004.01.05
---|Ветка была без названия|---


3-11776
S.A.S.
2003-12-09 13:44
2004.01.05
FIB, declare cursor


8-12002
pasha_676
2003-09-02 12:07
2004.01.05
FireWire видеомагнитофоны


3-11790
Dimaz-z
2003-12-08 21:57
2004.01.05
Проблема с кодировкой в ClientDataSet.


8-12008
xn0bys
2003-08-29 08:23
2004.01.05
Как создать на клиентской части формы БИТМАП (НЕ канву).





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский