Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.01.05;
Скачать: CL | DM;

Вниз

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

 
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;
Скачать: CL | DM;

Наверх




Память: 0.61 MB
Время: 0.03 c
9-11762
NAlexey
2003-06-11 09:30
2004.01.05
Пулевое отверстие и звук выстрела


14-12119
REA
2003-12-14 14:27
2004.01.05
Поймали?


1-11936
TEXHAPb
2003-12-20 14:09
2004.01.05
Не удаётся поставить компонент


1-11979
k_len
2003-12-19 11:04
2004.01.05
Округление


14-12111
quik
2003-12-14 13:01
2004.01.05
Компоненты