16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル
"RE:HTML の TABLE タグを解析(1)"
この発言は #00954 DUDE さんのHTLM の TABLE タグを解析 に対するコメントです
テーブル内のエラー回復の追加と、入れ子になったテーブルへの対応(15レベル
まで)、複数の HTML ファイルの繰り返し実行の許可、複数行のコメントへの対
応、テーブル以外の要素もツリーに表示するように改良を行いました。
たとえば次のような HTML は、
<HTML>
<HEAD>
<TITLE>Test HTML</TITLE>
</HEAD>
<BODY>
<TABLE>
<TR>
<TH>No.1</TH><TD>Good morning.<TABLE><TR><TD>Nested</TD></TABLE></TD>
<TR>
<TH>No.2</TH><TD>Good afternoon.</TD>
</TABLE>
</BODY>
</HTML>
このプログラムによって、以下のようなツリーとして表示できます(実際はツ
リービューコントロール)。
+-- <HTML><HEAD><TITLE>Test HTML</TITLE></HEAD><BODY>
|
+-- <TABLE>
| |
| +-- <TR>
| | |
| | +-- <TH>
| | | |
| | | +-- No.1
| | |
| | +-- <TD>
| | |
| | +-- Good morning.
| | |
| | +-- <TABLE>
| | |
| | +-- <TR>
| | |
| | +-- <TD>
| | |
| | +-- Nested
| +-- <TR>
| |
| +-- <TH>
| | |
| | +-- No.2
| |
| +-- <TD>
| |
| +-- Good afternoon.
|
+-- </BODY></HTML>
今回の文法定義では shift/reduce conflict は、主として文字列の扱いの部分
に出ています。これは、HTML において空白文字が場所によって無視される場合
と無視されない場合に対応するためです。いずれの場合も shift で切り抜けら
れ、問題も発生しないのでそのままとなっていますが、これを完全に回避するた
めには、字句解析における文字列の解釈を変更する必要があります。
たとえば、<TD> タグの要素である table_string は次のように定義しています
が、
table_string
: /* empty */
| table_string string
| table_string table
;
string
: CHAR
| SPACE
| string CHAR
| string SPACE
;
これは、下のような場合に conflict が発生します。
<TD>AB</TD>
最初の A は string として扱われますが、次の入力 B は、A に組み込む
string なのか(shift)、あるいは A の1文字で string を還元して
(reduce)、B は次の table_string の構成要素の string へ組み込むのか、あ
いまいです。
つまり、
AB = string -> table_string
AB = string string -> table_string
という2つの解釈があります。lex がタグ以外の文字を1文字ずつ返しているた
めにこのようなあいまいさが発生しています。
このような場合、yylex が AB を1つの文字列として返すといいのですが、今度
は lex 側でのタグの解析が複雑になってしまうので、悩ましいところです。
dfm ファイルも含めた完全版を、
http://member.nifty.ne.jp/dude/files/htmlp2.lzh
に置いておきました。
また、lexlib への修正については、#954 に書いたとおりです。
------------------------------------------------------------------------------
<---- token.l ----
%start INITIAL COMM
TABLE [Tt][Aa][Bb][Ll][Ee]
TR [Tt][Rr]
TH [Tt][Hh]
TD [Tt][Dd]
COMMENT [Cc][Oo][Mm][Mm][Ee][Nn][Tt]
%%
<INITIAL>"<"{TABLE}(">"|" "+[^>]*">") return(TABLE);
<INITIAL>"</"{TABLE}(">"|" "+[^>]*">") return(_TABLE);
<INITIAL>"<"{TR}(">"|" "+[^>]*">") return(TR);
<INITIAL>"</"{TR}(">"|" "+[^>]*">") return(_TR);
<INITIAL>"<"{TH}(">"|" "+[^>]*">") return(TH);
<INITIAL>"</"{TH}(">"|" "+[^>]*">") return(_TH);
<INITIAL>"<"{TD}(">"|" "+[^>]*">") return(TD);
<INITIAL>"</"{TD}(">"|" "+[^>]*">") return(_TD);
<INITIAL>"<!--" start(COMM);
<INITIAL>{COMMENT} start(COMM);
<COMM>"-->" start(INITIAL);
<COMM>"/"{COMMENT} start(INITIAL);
"\n" ; (* ignore *)
<INITIAL>[\t ]+ begin
yylval.yyShortString
:= yytext;
return(SP);
end;
<INITIAL>. begin
yylval.yyShortString
:= yytext;
return(CH);
end;
%%
begin
start(INITIAL);
end.
pars.y と main.pas が収まりきれなかったので、次の発言に続きます。
99/10/19(Tue) 08:43pm [AirCraft開発] PFF01344 DUDE
http://member.nifty.ne.jp/dude/
Original document by DUDE 氏 ID:(PFF01344)
ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。
Copyright 1996-2002 Delphi Users' Forum
|