Если Вы не знакомы с блоком try – finally то прочитайте эту статью: http://www.delphisources.ru/pages/faq/faq_delphi_basics/Try.php.html
TParser позволяет обрабатывать DFM файлы (.dfm - расширение), используется RAD Studio для их анализа.
Embarcadero о TParser:
http://docwiki.embarcadero.com/Libraries/en/System.Classes.TParser
Данный класс находиться в модуле Classes, вот его описание:
Пример очень прост и хорошо прокоментирован, при нажатии на кнопку «Парсить» мы создаём поток для передачи текста, который нам нужно проанализировать:
Ссылка на исходник:
http://www.fayloobmennik.net/1681798
Полезные ссылки:
Лексический анализ (Википедия):
http://ru.wikipedia.org/wiki/Лексема_(информатика)
Синтаксический анализ, парсер (Википедия):
http://ru.wikipedia.org/wiki/Парсер
Интерпретатор на коленке на основе TParser: (взята за основу, спасибо автору)
http://www.mirgames.ru/articles/base/tparser.html#part2_1
Использование TParser:
http://www.kansoftware.ru/?tid=4767
Пример TParser:
http://www.delphisources.ru/pages/faq/base/tparser_example.html
TParser позволяет обрабатывать DFM файлы (.dfm - расширение), используется RAD Studio для их анализа.
Embarcadero о TParser:
http://docwiki.embarcadero.com/Libraries/en/System.Classes.TParser
Данный класс находиться в модуле Classes, вот его описание:
{ TParser } TParserErrorEvent = procedure (Sender: TObject; const Message: string; var Handled: Boolean) of object; TParser = class(TObject) private type TCharType = (ctOther, ctLetterStart, ctLetterNumber, ctNumber, ctHash, ctQuote, ctDollar, ctDash); private FStream: TStream; FOrigin: Longint; FBuffer: TBytes; FBufPtr: Integer; FBufEnd: Integer; FSourcePtr: Integer; FSourceEnd: Integer; FTokenPtr: Integer; FStringPtr: Integer; FSourceLine: Integer; FSaveChar: Byte; FToken: Char; FFloatType: Char; FWideStr: UnicodeString; FOnError: TParserErrorEvent; FEncoding: TEncoding; FFormatSettings: TFormatSettings; procedure ReadBuffer; procedure SkipBlanks; function CharType(var ABufPos: Integer): TCharType; protected function GetLinePos: Integer; public constructor Create(Stream: TStream; AOnError: TParserErrorEvent = nil); overload; constructor Create(Stream: TStream; const FormatSettings: TFormatSettings; AOnError: TParserErrorEvent = nil); overload; destructor Destroy; override; procedure CheckToken(T: Char); procedure CheckTokenSymbol(const S: string); procedure Error(const Ident: string); procedure ErrorFmt(const Ident: string; const Args: array of const); procedure ErrorStr(const Message: string); procedure HexToBinary(Stream: TStream); function NextToken: Char; function SourcePos: Longint; function TokenComponentIdent: string; function TokenFloat: Extended; function TokenInt: Int64; function TokenString: string; function TokenWideString: UnicodeString; function TokenSymbolIs(const S: string): Boolean; property FloatType: Char read FFloatType; property SourceLine: Integer read FSourceLine; property LinePos: Integer read GetLinePos; property Token: Char read FToken; property OnError: TParserErrorEvent read FOnError write FOnError; end;А вот сама демка:
unit uDemo; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ComCtrls, IniFiles, ExtDlgs; type TLexeme = class LexemeType: Char; Value: string; Pos, Line: Integer; end; TFrm = class(TForm) BottomPanel: TPanel; btnOpen: TButton; btnParse: TButton; OpenTextFileDialog: TOpenTextFileDialog; PageControl: TPageControl; tsFile: TTabSheet; tsLexemsList: TTabSheet; RichEdit: TRichEdit; LeftPanel: TPanel; lbLexems: TListBox; RightPanel: TPanel; gbLexem: TGroupBox; lbMemo: TMemo; tsLexemsTree: TTabSheet; tvLexems: TTreeView; Label1: TLabel; Label2: TLabel; GroupBox1: TGroupBox; tvMemo: TMemo; procedure btnParseClick(Sender: TObject); procedure btnOpenClick(Sender: TObject); procedure lbLexemsClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure tvLexemsChange(Sender: TObject; Node: TTreeNode); private { Private declarations } procedure ShowLexemeInfo(Memo: TMemo; Lexeme: TLexeme); public { Public declarations } end; var Frm: TFrm; implementation {$R *.dfm} // Существует ли нода с таким именем в дереве function IsItemExist(TV: TTreeView; Name: string): Boolean; var I: Integer; begin Result := False; for I := 0 to TV.Items.Count - 1 do if TV.Items[I].Text = Name then Result := True; end; // Добавить ноду как "Root" function AddRootNode(TV: TTreeView; Name: string): TTreeNode; var Node: TTreeNode; begin Node := TV.Items.AddChild(nil, Name); Node.ImageIndex := 0; Node.SelectedIndex := 0; Result := Node; end; // Добавить ноду как "Child" function AddChildNode(TV: TTreeView; Name: string; Parent: TTreeNode): TTreeNode; var Node: TTreeNode; begin Node := TV.Items.AddChild(Parent, Name); Node.ImageIndex := 0; Node.SelectedIndex := 0; Result := Node; end; // Получаем тип лексемы как string function GetLexemeTypeAsString(Lexeme: TLexeme): string; begin Result := Lexeme.LexemeType; case Lexeme.LexemeType of Char(0): Result := 'EOF'; Char(1): Result := 'Symbol'; Char(2): Result := 'String'; Char(3): Result := 'Integer'; Char(4): Result := 'Float'; Char(5): Result := 'WString'; end; end; // Открыть procedure TFrm.btnOpenClick(Sender: TObject); begin if OpenTextFileDialog.Execute then begin RichEdit.Lines.Clear; lbLexems.Clear; tvLexems.Items.Clear; lbMemo.Clear; tvMemo.Clear; RichEdit.Lines.LoadFromFile(OpenTextFileDialog.FileName); end; end; // Парсить procedure TFrm.btnParseClick(Sender: TObject); var Stream: TStringStream; Parser: TParser; Temp: TLexeme; Node, Root: TTreeNode; begin if Length(RichEdit.Text) > 0 then begin lbLexems.Clear; tvLexems.Items.Clear; lbMemo.Clear; tvMemo.Clear; Stream := TStringStream.Create(RichEdit.Text); // записываем текст в поток try Parser := TParser.Create(Stream); // передаем поток парсеру try repeat Temp := TLexeme.Create; // создаём лексему // и заполняем её данными Temp.LexemeType := Parser.Token; // тип Temp.Value := Parser.TokenString; // значение Temp.Pos := Parser.SourcePos; // позиция Temp.Line := Parser.SourceLine; // линия lbLexems.AddItem(Temp.Value, Temp); // заносим в список // заносим в дерево tvLexems.Items.BeginUpdate; if not IsItemExist(tvLexems, IntToStr(Temp.Line)) then begin Root := AddRootNode(tvLexems, IntToStr(Temp.Line)); Node := AddChildNode(tvLexems, Temp.Value, Root); Node.Data := Temp; end else begin Node := AddChildNode(tvLexems, Temp.Value, Root); Node.Data := Temp; end; tvLexems.Items.EndUpdate; until Parser.NextToken = toEOF; // повторяем действия до конца текста finally Parser.Free; // не забываем освобождать память end; finally Stream.Free; // не забываем освобождать память end; end; Label1.Caption := 'Всего лексем: ' + IntToStr(lbLexems.Count); Label2.Caption := 'Всего строк: ' + IntToStr(RichEdit.Lines.Count); tvLexems.FullExpand; tvLexems.Select(tvLexems.Items.GetFirstNode); end; // Выводим данные в мемо procedure TFrm.ShowLexemeInfo(Memo: TMemo; Lexeme: TLexeme); begin Memo.Lines.Clear; Memo.Lines.Add('Строка - ' + RichEdit.Lines[Lexeme.Line - 1]); Memo.Lines.Add(''); Memo.Lines.Add('Значение: ' + Lexeme.Value); Memo.Lines.Add('Тип лексемы: ' + GetLexemeTypeAsString(Lexeme)); Memo.Lines.Add('№ строки: ' + IntToStr(Lexeme.Line)); Memo.Lines.Add('Позиция: ' + IntToStr(Lexeme.Pos)); end; // Выводим данные по выбраной лексеме в списке procedure TFrm.lbLexemsClick(Sender: TObject); var Temp: TLexeme; begin if lbLexems.ItemIndex >= 0 then begin Temp := lbLexems.Items.Objects[lbLexems.ItemIndex] as TLexeme; ShowLexemeInfo(lbMemo, Temp); end; end; // Выводим данные по выбраной лексеме в дереве procedure TFrm.tvLexemsChange(Sender: TObject; Node: TTreeNode); begin if Assigned(tvLexems.Selected) and (not tvLexems.Selected.HasChildren) then ShowLexemeInfo(tvMemo, TLexeme(tvLexems.Selected.Data)); end; procedure TFrm.FormCreate(Sender: TObject); begin btnParseClick(Sender); lbLexems.ItemIndex := 0; lbLexemsClick(Sender); end; end.
Пример очень прост и хорошо прокоментирован, при нажатии на кнопку «Парсить» мы создаём поток для передачи текста, который нам нужно проанализировать:
Stream := TStringStream.Create(RichEdit.Text);После чего передаём поток самому парсеру:
Parser := Tparser.Create(Stream);В цикле, до конца потока создаём экземпляры нашей лексемы:
Temp := TLexeme.Create;Заполняем её данными:
Temp.LexemeType := Parser.Token; // тип Temp.Value := Parser.TokenString; // значение Temp.Pos := Parser.SourcePos; // позиция Temp.Line := Parser.SourceLine; // линияЗаносим лексему в список (TList):
lbLexems.AddItem(Temp.Value, Temp);Заносим лексему в дерево (TTreeView)
tvLexems.Items.BeginUpdate; if not IsItemExist(tvLexems, IntToStr(Temp.Line)) then begin Root := AddRootNode(tvLexems, IntToStr(Temp.Line)); Node := AddChildNode(tvLexems, Temp.Value, Root); Node.Data := Temp; end else begin Node := AddChildNode(tvLexems, Temp.Value, Root); Node.Data := Temp; end; tvLexems.Items.EndUpdate;После чего освобождаем память:
Parser.Free; Stream.Free;
Ссылка на исходник:
http://www.fayloobmennik.net/1681798
Полезные ссылки:
Лексический анализ (Википедия):
http://ru.wikipedia.org/wiki/Лексема_(информатика)
Синтаксический анализ, парсер (Википедия):
http://ru.wikipedia.org/wiki/Парсер
Интерпретатор на коленке на основе TParser: (взята за основу, спасибо автору)
http://www.mirgames.ru/articles/base/tparser.html#part2_1
Использование TParser:
http://www.kansoftware.ru/?tid=4767
Пример TParser:
http://www.delphisources.ru/pages/faq/base/tparser_example.html
Комментариев нет:
Отправить комментарий