Анализатор Prolog-DCG со входом из файла

в рамках проекта мне нужно написать парсер, который может читать файл и анализировать факты, которые я могу использовать в своей программе.

структура файла выглядит следующим образом:

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.

to

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 элементами): Sentence split in parts

теперь я знаю, что многие люди здесь ссылаются на библиотеки dcg_basics и pio, когда дело доходит до dcgs. Однако у меня есть дополнительная проблема, что при попытке использовать библиотеку я получаю сообщение об ошибке:

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)].

дополнительная информация:

любой помощь в этом будет оценена!

EDIT: цель этого вопроса-узнать больше о DCG и его использовании в парсерах.

4 ответов


пока ваш файл находится в простом синтаксисе Prolog, вам рекомендуется использовать термин Prolog IO. Полностью структурированные термины читаются с помощью один звонок. Использование DCG его путь более сложный и немного менее эффективный (не уверен, что здесь следует измерять, но read (Term) вызывает парсер пролога, реализованный в C...) Этот другой вопрос, который использует тот же самый формат (по крайней мере, вы можете проверить, получил ли какой-то другой парень ответ здесь, так о вашем же назначение...)

редактировать после комментариев...

вы правы, что DCG являются право способ обработки общего анализа в прологе. Аргументы в производствах 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) мы можем применить семантическое Программирование к потокам пролога и получить вознаграждение за такое же поведение фразы/2.

больше

этой другого ответа показать практический способ реализации калькулятора выражений с разрешением оператора и ленивый оценка.


Ну, цель домашку учиться. Выполнение этого с DCG научит вас более полезному навыку, чем хорсинг операторов.

Я думаю, что ваши проблемы меньше с DCG по своей сути, чем с обработкой строк.

У вас есть куча мест, где вы используете univ (=.. operator) для преобразования между списками и строками. Univ, вероятно, не то, что вы хотите здесь. Университет объединяет термин со списком.

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

что нужно поймите, что строка в Prolog может быть в нескольких разных формах Строка "привет, Флорес" может быть

'привет Флорес' - это атом - "твердый кусок" вещи. Одинарные кавычки не нужны для некоторых последовательностей символов( см. вашу книгу), поэтому 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).  

в вашем файле, чтобы он печатал "привет, Флорис" в отладке, а не кучу чисел.

есть также список из одного символа атомы!--4-->

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

но вы, вероятно,не хотите их.

вы можете найти sicstus compatability pred read_line полезным.

Теперь, в DCG, вы иногда хотите соответствовать "литералам" - буквально этой вещи. Если да, внесите это в список. Вот DCG для операторов if на каком-то неопределенно VBish языке

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).

to

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}. Это будет не так уж сложно и легко прочесть.


IMHO, правила грамматики DCG довольно уродливы при токенизации, я действительно думаю, что DCG никогда не должен был даже предлагаться для этой задачи; реальная сделка с DCG заключается в анализе токенов, потому что prolog использует символику, поэтому я могу сказать, что лучший вариант-создать иностранный вызов, скажем, c tokenizer, который объединится с простым списком токенов, а затем пусть 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].

I подумайте, что это намного более элегантно,и ваши правила соответствуют. Я могу ошибаться в своих мыслях, но в конце концов это вопрос вкуса, и для меня DCG не является токенизатором, и я никогда не буду использовать его для этого, если это строго не требуется. По общему признанию, я могу найти некоторые приложения, где было бы целесообразно использовать его также как токенизатор, но все же я думаю, что задачи должны быть разделены.

обратите внимание, что я не говорю, что у prolog нет хороших возможностей, вы всегда можете это сделать токенизация в прологе, но вы должны разделить задачи и позволить DCG иметь дело только с символами и некоторыми другими строго необходимыми символами или строками (как строки верхнего регистра, например, имена собственные или другие символы).

наконец, мне кажется, что люди, возможно, забыли, что токенизация и синтаксический анализ-это две отдельные задачи; больше в прологе, так как токены-это символы, в которых пролог хорош, и разбор токенов / символов (не символов), что DCG делает лучше, для как embeeded семантики интерфейсы prolog, который является желаемым сценарием.