Parsing Prolog-DCG解析器,具有来自文件的输入

Parsing Prolog-DCG解析器,具有来自文件的输入,parsing,prolog,swi-prolog,dcg,Parsing,Prolog,Swi Prolog,Dcg,作为项目的一部分,我需要编写一个解析器,它可以读取文件并解析为我可以在程序中使用的事实 文件结构如下所示: property = { el1 , el2 , ... }. 我最终想要的是: property(el1). property(el2). ... 我这样读我的文件: main :- open('myFile.txt', read, Str), read_file(Str,Lines), close(Str), write(

作为项目的一部分,我需要编写一个解析器,它可以读取文件并解析为我可以在程序中使用的事实

文件结构如下所示:

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.

为此:

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个以上的元素):

现在我知道这里的很多人在谈到dcg时都会提到图书馆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)].
其他信息:

  • 我在Windows环境中使用该程序
在此方面的任何帮助都将不胜感激


编辑:这个问题的目的是了解更多关于DCG及其在解析器中的使用。

只要您的文件是纯Prolog语法,建议您使用Prolog术语IO。完全结构化的术语只需一次调用即可阅读。使用DCG的方式更复杂,效率稍低(这里不确定,应该测量,但是read(Term)调用了一个用C实现的Prolog解析器…)看看另一个,它使用非常相同的格式(至少,你可以检查是否有其他人在这里得到了关于你的相同任务的答案…)

评论后编辑

您是对的,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(),我们可以将语义编程应用于Prolog流,并获得与短语/2相同的行为奖励

更多


这展示了一种实现表达式计算器的实用方法,该计算器具有运算符分辨率和惰性计算。

嗯,家庭作业问题的目的是学习。使用DCG将教给您一种更普遍的有用技能,而不是让操作员操心

我认为DCG本身的问题比字符串处理的问题要少

有很多地方使用univ(=…运算符)在列表和字符串之间进行转换。大学可能不是你想要的。大学将一个术语与一个列表统一起来

foo(bar, baz)  =..  [foo, bar, baz]
您需要了解的是,Prolog中的字符串可以有几种不同的形式 “hi Flores”这个字符串可能是

“嗨,弗洛雷斯”-这是一个原子-一个“固体块”的东西。一些字符序列不需要单引号(参见您的书),因此hi_flores是一个非常好的atom 没有单引号

[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]

但你可能不想要这些

您可能会发现SICSTUS兼容性pred read_line很有用

现在,在DCG中,有时需要匹配“文字”——字面上就是这样。 如果是的话,把它列在一个列表中。 这里有一个DCG,它用一些模糊的VBish语言表示if语句

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's everywhere是可选的空白

现在,对于整体策略,您可以一次读取一行,也可以读取整个文件。对于一行,使用read_line,它返回代码列表。读取\u文件\u到\u代码将获得整个文件

如果使用全文件策略,并且换行符很重要,那么显然需要将它们从空白的定义中删除


当然,所有这些都引出了一个问题,为什么关于这个问题的问题会泛滥,而不是讲师的收件箱。

我将字符串解析为一个列表,然后操纵该列表。 使用DCG,您可以转换

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

注意事项:

1. parseLine(<<Yourpattern>>,Position) --> parseLine(L,Position), parseLine(R,NewPosition)
2. parseLine(Item,Pos) --> [Item-Pos].
1。parseLine(,位置)-->parseLine(L,位置),parseLine(R,新位置)
2.解析行(项目,位置)--->[项目位置]。

这里有两种模式需要处理,它们是(L>R)和{L,R}。这不会太复杂,而且很容易阅读

IMHO,DCG语法规则在标记化方面非常糟糕,我真的认为DCG根本不应该被用于该任务;DCG的真正任务是解析令牌,因为prolog使用符号,所以我可以说,最好的选择是创建一个对a(比如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不是一个标记器,除非严格要求,否则我永远不会使用它。令人钦佩的是,我可以发现一些应用程序,在这些应用程序中,也可以将其用作标记器,但是
 tokenize(A,ListOfTokens), phrase(yourDGCstartRule(Information), ListOfTokens, _).
ListOfTokens = [object,:,object,in,a,yields,b,',',object,in,b,yields,c].