簡體   English   中英

Prolog - 帶有文件輸入的 DCG 解析器

[英]Prolog - DCG parser with input from file

作為項目的一部分,我需要編寫一個解析器,它可以讀取文件並將其解析為可以在我的程序中使用的事實。

文件結構如下所示:

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,所以任何關於這方面的幫助將不勝感激。 現在我遇到的問題是,如何對列表中的多個元素執行此操作,以及如何處理“{”和“}”。
我真正想要的是一個 dcg 可以處理這些類型的句子(超過 2 個元素):句子分成幾部分

現在我知道這里有很多人在談到 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 及其在解析器中的使用。

只要您的文件是純 Prolog 語法,建議您使用 Prolog 術語 IO。 只需一次調用即可閱讀完全結構化的術語。 使用 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).

感謝庫( pureio ),我們可以將語義編程應用於 Prolog 流,並獲得與短語/2 相同的行為的獎勵。

更多的

這個另一個答案顯示了一種實用的方法來實現具有運算符解析和惰性求值的表達式計算器。

嗯,家庭作業問題的目的是學習。 用 DCG 做這件事會教你一個比馬術操作員更有用的技能。

我認為您的問題與 DCG 本身有關,而不是與字符串處理有關。

您有很多地方可以使用 univ(=.. 運算符)在列表和字符串之間進行轉換。 大學可能不是你想要的。 Univ 將術語與列表統一起來。

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

您需要了解的是 Prolog 中的字符串可以有幾種不同的形式 字符串 'hi Flores' 可以是

'嗨弗洛雷斯' - 這是一個原子 - 一個“固體塊”的東西。 某些字符序列不需要單引號(請參閱您的書),因此 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).  

在您的文件中,因此它會在調試中打印出“hi Floris”,而不是一堆數字。

還有一個包含一個字符的原子列表

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

但你可能不想要那些。

您可能會發現 SISTUS 兼容性 pred read_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 到處都是可選的空格。

現在,對於整體策略,您可以一次讀取一行,也可以讀取整個文件。 對於一行,使用 read_line,它返回一個代碼列表。 read_file_to_codes 將獲得整個文件。

如果您使用整個文件策略,並且換行符很重要,那么顯然您需要將它們從空格的定義中刪除。

而且,當然,所有這些都會引出一個問題,為什么關於這個問題的問題會泛濫成災,而不是教師的信箱。

我將字符串解析為一個列表,然后操作該列表。 使用 DCG,您可以轉換

T = (saf>{saf, as13s}>a32s>asf).

S = [saf-0, saf-1, as13s-1, a32s-2, asf-3] .

注意事項:

1. parseLine(<<Yourpattern>>,Position) --> parseLine(L,Position), parseLine(R,NewPosition)
2. parseLine(Item,Pos) --> [Item-Pos].

在這里你有 2 種模式來處理那些是 (L>R) 和 {L,R}。 這不會太復雜,而且非常容易閱讀。

恕我直言,DCG 語法規則在標記化方面非常丑陋,我真的認為 DCG 甚至不應該被提議用於該任務; DCG 的真正處理是解析標記,因為 prolog 使用符號,所以我可以說,最好的選擇是創建一個外部調用,比如 C 標記器,它將與標記的簡單列表統一,然后讓 DCG做它一直雖然。 這樣實現更干凈,你不必擔心解析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 不是標記器,除非嚴格要求,否則我永遠不會使用它。 誠然,我可以發現一些應用程序,將它也用作標記器是有意義的,但我仍然認為任務應該分開。

請注意,我並不是說 prolog 沒有很好的設施,您總是可以在 prolog 中進行標記化,但您應該將任務分開,讓 DCG 僅處理符號和其他一些嚴格需要的字符或字符串(如大寫字符串,例如專有名稱或其他字符)。

最后,在我看來,人們可能已經忘記了標記和解析是兩個獨立的任務; 在 prolog 中更多,因為標記是 prolog 擅長的符號,並且解析標記/符號(不是字符)DCG 做得更好,因為作為嵌入語義接口 prolog,這是理想的場景。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM