Форум: "Основная";
Текущий архив: 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