12

プロジェクトの一環として、ファイルを読み取り、プログラムで使用できる事実に解析できるパーサーを作成する必要があります。

ファイル構造は次のようになります。

property = { el1 , el2 , ... }.  

私が最後に欲しいのは:

property(el1).
property(el2).
...

私は次のようにファイルを読みました:

main :-
       open('myFile.txt', read, Str),
       read_file(Str,Lines),
       close(Str),
       write(Lines), nl.

read_file(Stream,[]) :-
                       at_end_of_stream(Stream).

read_file(Stream,[X|L]) :-
                          \+ at_end_of_stream(Stream),
                          read(Stream,X),
                          parse(X),            % Here I call upon my parser.
                          read_file(Stream,L).

今、私はDCGについていくつかの本とオンラインを読みましたが、それらはすべて、「猫はコウモリを食べる」などの文を生成できる同じ簡単な例を説明しています...上記の例にそれを使用したいとき、私は惨めに失敗します.

私が管理したのは、下の行を「解析」することでした:

property = el1.

property(el1).

これとともに:

parse(X) :-
           X =.. List,    % Reason I do this is because X is one atom and not a list.
           phrase(sentence(Statement), List),
           asserta(Statement).

sentence(Statement) --> ['=', Gender, Person] , { Statement =.. [Gender, Person] }.

ここでdcgを正しい方法で使用しているかどうかさえわからないので、これに関するヘルプをいただければ幸いです。今私が抱えている問題は、リスト内の複数の要素でこれを行う方法と、「{」と「}」を処理する方法です。
私が本当に欲しいのは、これらのタイプの文 (2 つ以上の要素を持つ) を処理できる dcg です。部分に分割された文

dcgs に関しては、このあたりの多くの人がライブラリ dcg_basics と pio を参照していることを知っています。ただし、ライブラリを使用しようとするとエラーが発生するという追加の問題があります。

ERROR: (c:/users/ldevriendt/documents/prolog/file3.pl:3):
      Type error: `text' expected, found `http/dcg_basics'
Warning: (c:/users/ldevriendt/documents/prolog/file3.pl:3):
      Goal (directive) failed: user:[library(http/dcg_basics)]

私がこれを行うとき:

:- [library(http/dcg_basics)].

追加情報:

これに関するヘルプをいただければ幸いです。

編集:この質問の目的は、DCG とそのパーサーでの使用について詳しく知ることです。

4

4 に答える 4

13

ファイルがプレーンな Prolog 構文である限り、Prolog 用語 IO を使用することをお勧めします。完全に構造化された用語は、1 回の呼び出しで読み取られます。DCG を使用すると、その方法がより複雑になり、効率が少し低下します (ここではわかりませんが、測定する必要がありますが、read(Term) は C で実装された Prolog パーサーを呼び出します...)まったく同じ形式を使用するこの他の質問を参照してください (少なくとも、他の人があなたの同じ課題について SO で回答を得たかどうかを確認できます...)

コメントの後に編集...

DCG がProlog で一般的な解析を処理する正しい方法であることは間違いありません。DCG プロダクションの引数はセマンティック属性と見なすことができるため、DCG のプログラミングは、入力に対して有効なセマンティック分析を提供するものと見なすことができます (言語工学においても重要な手法である属性文法を参照してください)。

実際、提示された例は、用語 IO で必要なハックなしで完全に解決できます。

ここにあります:

:- use_module(library(pio)).  % autoload(ed), added just for easy browsing
:- use_module(library(dcg/basics)).

property(P) -->
    b, "my props", b, "=", b, "{", elS(Es) , b, "}", b,
    { P =.. [property|Es] }.

elS([E|Es]) --> el(E), b, ("," -> elS(Es) ; {Es = []}).
el(N) --> number(N).
el(S) --> csym(S). % after Jeremy Knees comment...
b --> blanks.

%   parse a C symbol
csym(S) -->
    [F], { code_type(F, csymf) },
    csym1(Cs),
    !, { atom_codes(S, [F|Cs]) }.

csym1([C|Cs]) -->
    [C], { code_type(C, csym) },
    csym1(Cs).
csym1([]) --> [].

それで、私たちは持っています

?- phrase(property(P), "my props = {1,2,3}").
P = property(1, 2, 3).

library( pureio )のおかげで、セマンティック プログラミングを Prolog ストリームに適用することができ、phrase/2 と同じ動作が得られます。

もっと

この他の回答は、演算子の解決と遅延評価を使用して式計算機を実装する実用的な方法を示しています。

于 2012-12-24T18:01:02.800 に答える
1

さて、宿題の質問の目的は学ぶことです。DCGを使用してそれを行うと、オペレーターを馬鹿にするよりも一般的に役立つスキルが得られます。

あなたの問題は、文字列処理よりも本質的にDCGの方が少ないと思います。

univ(= ..演算子)を使用してリストと文字列を変換する場所がたくさんあります。大学はおそらくあなたがここで望んでいるものではありません。大学は用語をリストと統合します。

foo(bar, baz)  =..  [foo, bar, baz]

あなたが理解する必要があるのは、Prologの文字列はいくつかの異なる形式である可能性があるということです文字列「hiFlores」は

「こんにちはフローレス」-これは原子です-物の「固体の塊」。一部の文字シーケンスでは一重引用符は必要ありません(本を参照)。したがって、hi_floresは、一重引用符がなくても完全に優れたアトムです。

[104,105,32,70,108,111,114,101,115] - a list of ASCII codes.  This is likely what you want. These can be written with double quotes, "hi Floris"  in prolog code.

To save your sanity, put

:- portray_text(true).  

ファイルに含めると、大量の数字ではなく、デバッグで「hiFloris」が出力されます。

1文字の原子のリストもあります

[h、i、''、'F'、l、o、r、i、s]

しかし、あなたはおそらくそれらを望まないでしょう。

SICSTUSの互換性predread_lineが役立つ場合があります。

さて、DCGでは、「リテラル」と一致させたい場合があります。文字通りそのことです。もしそうなら、それをリストに入れてください。これは、漠然としたVBish言語のifステートメントのDCGです。

if_statement  --> "if", wh, "(", condition, ")", wh, 
                  "then", wh, body, wh, "else", wh,
                  else_body, wh, "endif".

% whitespace
wh -->  [].
wh -->  " ", wh.
wh --> [10], wh.   % handle newline and cr
wh --> [12], wh.

どこにでもあるwhはオプションの空白です。

これで、全体的な戦略として、一度に1行ずつ読み取ることも、ファイル全体を読み取ることもできます。1行には、コードのリストを返すread_lineを使用します。read_file_to_codesはファイル全体を取得します。

ファイル戦略全体を使用し、改行が重要である場合は、明らかに空白の定義から改行を削除する必要があります。

そしてもちろん、これはすべて、この問題に関する質問が、インストラクターのボックスではなく、SOに殺到している理由の疑問につながります。

于 2012-12-26T04:45:31.173 に答える
0

私見ですが、DCG の文法規則はトークン化に関しては非常に醜いものです。プロローグはシンボリックを使用するため、DCGの実際の取引はトークンを解析することです。したがって、最良のオプションは、トークンのプレーンリストと統合してDCGを許可するCトークナイザーなどへの外部呼び出しを作成することです。それがされていることを行います。このようにして、実装がよりクリーンになり、cr、空白の解析について心配する必要がなくなります...

次のようなステートメントを持つ架空の言語があるとします。

object:
       object in a yields b,
       object in b yields C.

これを DCG でトークン化することを想像したくありません。そのようなタスク用に設計されていないツールでそうする方法を学ぶのが面倒です。トークンの単純なリストを提供する述語への外部呼び出しを行う方がよいでしょう。

 tokenize(A,ListOfTokens), phrase(yourDGCstartRule(Information), ListOfTokens, _).

実行例のリストは次のようになります。

ListOfTokens = [object,:,object,in,a,yields,b,',',object,in,b,yields,c].

これははるかにエレガントであり、それに応じてルールがマップされると思います。私の考えでは間違っているかもしれませんが、最終的には好みの問題であり、私にとって DCG はトークナイザーではなく、厳密に必要とされない限り、そのために使用することはありません。確かに、トークナイザーとしても使用することが理にかなっているアプリケーションをいくつか見つけることができますが、それでもタスクを分離する必要があると思います。

プロローグには良い機能がないと言っているわけではないことに注意してください。プロローグでいつでもトークン化を行うことができますが、タスクを分離し、DCG にシンボルとその他の厳密に必要な文字または文字列 (大文字の文字列など) のみを処理させる必要があります。固有名詞またはその他の文字)。

最後に、トークン化と解析は 2 つの別個のタスクであることを人々が忘れているように思えます。プロローグでは、トークンはプロローグが得意とするシンボルであり、トークン/シンボル (文字ではない) の解析は、DCG がより優れているため、組み込みセマンティクス インターフェイス プロローグは望ましいシナリオです。

于 2013-04-28T09:06:52.343 に答える