Защо тази много проста граматика кара GLR анализаторите да се задавят?

Опитах няколко различни генератора на анализатори (Bison, DParser и т.н.), които твърдят, че могат да генерират анализатори на GLR, т.е. такива, които могат да обработват двусмислени граматики. Ето една много проста двусмислена граматика от типа, за който говоря:

START: A | B;
A: C | D;
B: C | D;
C: T1 | T2;
D: T3 | T4;
T1: 't1';
T2: 't2';
T3: 't3';
T4: 't4';

Мога да генерирам синтактичните анализатори добре, но получавам грешки „неразрешена двусмисленост“ или просто категорични сривове, когато дам вход на парсера, който трябва да е валиден. Няма проблеми от какъвто и да е вид, когато променям граматиката към недвусмислена версия.

Какво не разбирам за анализаторите на GLR? Мислех, че целият смисъл е, че в случаи на неяснота ВСИЧКИ възможни анализи се проследяват, докато не се слеят или стигнат до задънена улица. Всичко, от което се нуждая, е анализатор, който може да ми каже дали има НЯКАКВО валиден анализ на входа.

Благодаря за всяка помощ.

редактиране:

Това е разочароващо. С помощта на %dprec и %merge успях да накарам Bison да обработва двусмислени правила и терминали, но той все още се задушава от много прости, но силно патологични псевдоанглийски граматики от вида, с който трябва да се справя:

S: NP VP | NPA VP;
NPA: D N | NP PP;
NP: D N | NP PP | NPA;
VP: V NP | VP PP;
PP: P NP;
D: "the" | "a";
P: "in" | "with";
V: "saw";
N: "saw" | "girl" | "boy" | "park" | "telescope";

С вход „момче видя момиче“, Bison не може да анализира и се връща с код 1. Том, от друга страна, се справя безупречно с тази граматика и това въведено изречение и дори естествено обработва непознати терминали, като просто ги присвоява на всички възможни типове терминали. Но за разлика от Bison, Tom се задавя от големи граматики. (Под „дросели“ имам предвид откази по различни различни начини. Ако режимите на отказ биха били полезни, мога да ги докладвам.)

Някой има ли други идеи?


person user3268289    schedule 20.02.2014    source източник


Отговори (2)


За съжаление, bison наистина настоява за създаване на (единичен) анализ, така че трябва да посочите някакъв начин за обединяване на двусмислени анализи. Ако не го направите и има повече от един възможен анализ, GLR анализаторът на bison наистина ще се оплаче, че анализът е двусмислен.

Ако наистина не ви интересува кой от множеството анализи се приема, тогава не е твърде трудно да подчините bison на волята си. Най-простият начин е просто да присвоите различен %dprec на всяко евентуално двусмислено производство. След това Bison ще избере коя приложима продукция има най-добър приоритет.

Можете дори да накарате bison да ви каже за множество анализи с проста функция %merge; има пример в ръководството на bison. (Документацията за тази функция не е страхотна, но може да е подходяща за вашите нужди. Ако не, не се колебайте да зададете по-конкретен въпрос.)

Нямам много опит с DParser, но ръководството показва, че поведението му при с множество възможни анализи е подобно: по подразбиране е да се оплаквате, но можете да предоставите своя собствена тривиална функция за сливане: (Цитатът идва от Раздел 12, Неясноти)

Неяснотите се разрешават автоматично въз основа на приоритети и асоциации. В допълнение, когато другите техники за разрешаване не успеят, е възможно дефинирано от потребителя разрешаване на неяснота. Манипулаторът на неяснота по подразбиране създава фатална грешка при неразрешена неяснота. Това поведение може да бъде заменено с дефинирани от потребителя резолвери, чийто подпис е предоставен в dparse.h.


Ето примерна граматика на bison GLR за втория пример. Пропуснах лексера, който наистина не е уместен (и леко неудобно, защото бързах).

%{
  int yylex();
  void yyerror(const char* msg);
%}

%error-verbose
%glr-parser

%token WORD_A "a"
%token WORD_BOY "boy"
%token WORD_GIRL "girl"
%token WORD_IN "in"
%token WORD_LIKED "liked"
%token WORD_PARK "park"
%token WORD_SAW "saw"
%token WORD_TELESCOPE "telescope"
%token WORD_THE "the"
%token WORD_WITH "with"

%%
S  : NP VP      {puts("S: NP VP");}     %dprec 1
   | NPA VP     {puts("S: NPA VP");}    %dprec 2
   ;
NPA: D N        {puts("NPA: D N");}     %dprec 3
   | NP PP      {puts("NPA: NP PP");}   %dprec 4
   ;
NP : D N        {puts("NP: D N");}      %dprec 6
   | NP PP      {puts("NP: NP PP");}    %dprec 7
   | NPA        {puts("NP: NPA");}      %dprec 10
   ;
VP : V NP       {puts("VP: V NP ");}    %dprec 11
   | VP PP      {puts("VP: VP PP");}    %dprec 12
   ;
PP : P NP       {puts("PP: P NP");}     %dprec 14
   ;
D  : "the"      {puts("D: the");}       %dprec 15
   | "a"        {puts("D: a");}         %dprec 16
   ;
P  : "in"       {puts("P: in");}        %dprec 17
   | "with"     {puts("P: with");}      %dprec 18
   ;
V  : "liked"    {puts("V: liked");}     %dprec 19
   | "saw"      {puts("V: saw");}       %dprec 20
   ;
N  : "girl"     {puts("N: girl");}      %dprec 21
   | "boy"      {puts("N: boy");}       %dprec 22
   | "park"     {puts("N: park");}      %dprec 23
   | "saw"      {puts("N: saw");}       %dprec 24
   | "telescope"{puts("N: telescope");} %dprec 25
   ;
%%

int main(int argc, char** argv) {
  printf("yyparse returned %d\n", yyparse());
  return 0;
}

Компилация:

$ make ambig2
bison30 -v -d -o ambig2.c ambig2.y 
ambig2.y: warning: 6 shift/reduce conflicts [-Wconflicts-sr]
ambig2.y: warning: 10 reduce/reduce conflicts [-Wconflicts-rr]
gcc-4.8 -ggdb -Wall -D_POSIX_C_SOURCE=200809L -std=c99 -c -o ambig2.o ambig2.c
gcc-4.8   ambig2.o   -o ambig2
rm ambig2.o ambig2.c

Примерни анализи:

$ ./ambig2 <<<"a boy saw a girl"
D: a
N: boy
NPA: D N
V: saw
D: a
N: girl
NPA: D N
NP: NPA
VP: V NP 
S: NPA VP
yyparse returned 0

$ ./ambig2 <<<"a saw saw the saw in a saw"
D: a
N: saw
NPA: D N
V: saw
D: the
N: saw
NPA: D N
NP: NPA
VP: V NP 
P: in
D: a
N: saw
NPA: D N
NP: NPA
PP: P NP
VP: VP PP
S: NPA VP
yyparse returned 0
person rici    schedule 20.02.2014
comment
Благодаря за вашия отговор. Ще разгледам по-внимателно как да кажа на Bison и DParser как да разрешават неясноти. Надяваме се, че мога да кажа нещо като: if(ambiguity) { do nothing; } Междувременно намерих този древен, мъничък (~700 реда чист C) анализатор, наречен Tom (cs.cmu.edu/afs/cs/project/ai-repository/ai/areas/nlp/parsing/), че досега се справя перфектно с всичко, което му хвърля. Може би всички много по-любовни момчета като Bison са много по-големи, защото се занимават с ефективно анализиране, от което аз нямам нужда. - person user3268289; 20.02.2014
comment
@user3268289: И в двата случая рутинната процедура за неяснота се извиква само ако има неяснота и не може да направи нищо. Така че да, доста е просто. Въпреки че bison, разбира се, е загрижен за ефективността, основната причина за поведението му е, че той се занимава с анализиране на реални езици за целите на компилация/интерпретация, а те обикновено изискват недвусмислен анализ. Решението %dprec изисква много писане, но иначе е тривиално; просто добавете %dprec N в края на всяка продукция, където N е уникално цяло число (можете да ги номерирате последователно, например.) - person rici; 20.02.2014
comment
Ричи, твоите идеи бяха добри и подобриха работата на Bison с някои неприятни граматики. Въпреки това все още не работи за някои случаи, както във втория пример в първоначалния въпрос по-горе. - person user3268289; 21.02.2014
comment
Ричи, съжалявам, предполагам, че си видял версия на втория пример, докато го редактирах. Можете ли да накарате най-новата версия на втория пример (с телескоп за момиче и момче и т.н.) да работи? Между другото наистина оценявам вашата помощ. - person user3268289; 21.02.2014
comment
@user3268289: Вашият втори пример включва NP: NP, който (странно) не се премахва от glr парсера на bison и следователно създава безкраен цикъл. Освен това същата трансформация изглежда работи. С какъв вход имате проблеми? Между другото, бих изброил saw и като N, и като V, вместо да го поставя в отделна граматична категория, но може би пропускам мисълта ви. (О, и нямате Vs) - person rici; 21.02.2014
comment
Съжалявам, това е, което получавам, когато редактирам и изпробвам нещата едновременно. Вторият пример сега трябва да е правилен. Bison не може да се справи, но Tom може. Не знам защо. - person user3268289; 21.02.2014
comment
@user3268289: Окей-доки, ето го. - person rici; 21.02.2014
comment
Благодаря много Rici, оценявам помощта ви. Изглежда, че имах проблеми с моя токенизатор/лексер, а не с граматиката, както си мислех. Сега работи чудесно в Bison, въпреки че бързо научавам, че Bison и свързаните с него инструменти не са подходящи за НЛП, което наистина се опитвам да направя. - person user3268289; 23.02.2014

Вашата граматика не кара GLR анализаторите да се задавят.

Имате нужда от машина за анализиране на GLR, която предоставя това, което анализаторите на GLR трябва да доставят: анализиране в лицето на неясноти и предоставяне на резултата. Вероятно използвате допълнителен контекст, за да разрешите неяснотите. (Можете да забъркате проверката на контекста в процеса на анализиране, ако наистина настоявате да избягвате създаването на предотвратени от контекста неясноти. Ако направите това, получавате усложненията, каквито имаха момчетата от GCC, когато се опитаха да анализират C и C++ с LALR).

Ето изхода за проблема на OP, даден на генератора на GLR парсер на нашия DMS Software Reengineering Toolkit. Трябваше да дефинирам лексер и граматика, съвместими за DMS:

Lexer (дефиниране на отделни токени като думи; по-мащабируема версия може да е дефинирала токени от клас думи като D P V N):

%%
%%main
#skip "\s+"
#skip "[\u000d\u000a]+"
#token 'the' "the"
#token 'a' "a"
#token 'in' "in"
#token 'with' "with"
#token 'saw' "saw"
#token 'girl' "girl"
#token 'boy' "boy"
#token 'park' "park"
#token 'telescope' "telescope"
%%

Граматика (DMS не се занимава с EBNF):

S = NP VP ;
S = NPA VP ;
NPA = D N ;
NPA = NP PP ;
NP = D N ;
NP = NP PP ;
NP = NPA ;
VP = V NP ;
VP = VP PP ;
PP = P NP ;
D = 'the' ;
D = 'a';
P = 'in' ;
P = 'with' ;
V = 'saw' ;
N = 'saw' ;
N = 'girl' ;
N = 'boy' ;
N = 'park' ;
N = 'telescope' ;

Примерен файл "aboysawagirl.txt"

a boy saw a girl\n

От началото до края, изграждане на лексер и анализатор (около 10 минути бъркане...)

Разбор на примерния файл и изхвърляне на автоматично създаденото дърво:

C:\DMS\Domains\simpenglish\Tools\Parser\Source>run ..\domainparser ++AST ..\..\Lexer\aboysawagirl.txt
simpenglish Domain Parser Version 2.5.15
Copyright (C) 1996-2013 Semantic Designs, Inc; All Rights Reserved; SD Confidential
Powered by DMS (R) Software Reengineering Toolkit
24 tree nodes in tree.
3 ambiguity nodes in tree.
(AMBIGUITY<S=11>@simpenglish=31@#1f35140^0{2} Line 1 Column 1 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
 (S@simpenglish=1@#1f350e0^1#1f35140:1 Line 1 Column 1 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
  (AMBIGUITY<NP=12>@simpenglish=31@#1f34ba0^1#1f350e0:1{2} Line 1 Column 1 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   (NP@simpenglish=5@#1f34b80^1#1f34ba0:1 Line 1 Column 1 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   |(D@simpenglish=12@#1f34aa0^2#1f34b80:1#1f34b40:1 Line 1 Column 1 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   | ('a'@simpenglish=22@#1f349c0^1#1f34aa0:1[Keyword:0] Line 1 Column 1 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt)'a'
   |)D#1f34aa0
   |(N@simpenglish=18@#1f34b20^2#1f34b80:2#1f34b40:2 Line 1 Column 3 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   | ('boy'@simpenglish=27@#1f34a80^1#1f34b20:1[Keyword:0] Line 1 Column 3 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt)'boy'
   |)N#1f34b20
   )NP#1f34b80
   (NP@simpenglish=7@#1f34c60^1#1f34ba0:2 Line 1 Column 1 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   |(NPA@simpenglish=3@#1f34b40^2#1f35040:1#1f34c60:1 Line 1 Column 1 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   | (D@simpenglish=12@#1f34aa0^2... [ALREADY PRINTED] ...)
   | (N@simpenglish=18@#1f34b20^2... [ALREADY PRINTED] ...)
   |)NPA#1f34b40
   )NP#1f34c60
  )AMBIGUITY#1f34ba0
  (VP@simpenglish=8@#1f34fc0^1#1f350e0:2 Line 1 Column 7 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   (V@simpenglish=15@#1f34d60^1#1f34fc0:1 Line 1 Column 7 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   |('saw'@simpenglish=25@#1f34b00^2#1f34d60:1#1f34d40:1[Keyword:0] Line 1 Column 7 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt)'saw'
   )V#1f34d60
   (AMBIGUITY<NP=12>@simpenglish=31@#1f34f00^2#1f34f80:2#1f34fc0:2{2} Line 1 Column 11 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   |(NP@simpenglish=5@#1f34e60^1#1f34f00:1 Line 1 Column 11 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   | (D@simpenglish=12@#1f34da0^2#1f34e60:1#1f34de0:1 Line 1 Column 11 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   |  ('a'@simpenglish=22@#1f34ce0^1#1f34da0:1[Keyword:0] Line 1 Column 11 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt)'a'
   | )D#1f34da0
   | (N@simpenglish=17@#1f34dc0^2#1f34e60:2#1f34de0:2 Line 1 Column 13 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   |  ('girl'@simpenglish=26@#1f34d80^1#1f34dc0:1[Keyword:0] Line 1 Column 13 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt)'girl'
   | )N#1f34dc0
   |)NP#1f34e60
   |(NP@simpenglish=7@#1f34f20^1#1f34f00:2 Line 1 Column 11 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   | (NPA@simpenglish=3@#1f34de0^1#1f34f20:1 Line 1 Column 11 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   |  (D@simpenglish=12@#1f34da0^2... [ALREADY PRINTED] ...)
   |  (N@simpenglish=17@#1f34dc0^2... [ALREADY PRINTED] ...)
   | )NPA#1f34de0
   |)NP#1f34f20
   )AMBIGUITY#1f34f00
  )VP#1f34fc0
 )S#1f350e0
 (S@simpenglish=2@#1f35040^1#1f35140:2 Line 1 Column 1 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
  (NPA@simpenglish=3@#1f34b40^2... [ALREADY PRINTED] ...)
  (VP@simpenglish=8@#1f34f80^1#1f35040:2 Line 1 Column 7 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   (V@simpenglish=15@#1f34d40^1#1f34f80:1 Line 1 Column 7 File C:/DMS/Domains/simpenglish/Tools/Lexer/aboysawagirl.txt
   |('saw'@simpenglish=25@#1f34b00^2... [ALREADY PRINTED] ...)
   )V#1f34d40
   (AMBIGUITY<NP=12>@simpenglish=31@#1f34f00^2... [ALREADY PRINTED] ...)
  )VP#1f34f80
 )S#1f35040
)AMBIGUITY#1f35140

Вашият прост анализатор на английската граматика анализира вашето примерно изречение по различни начини.

Това е много по-зрелищно с пълна граматика на C++11.

person Ira Baxter    schedule 20.02.2014