Рекурсивний синтаксичний аналізатор з відстеженням граматики


10

Чи може хтось просвітити мене, чому рекурсивний аналізатор спуску з відстеженням, який намагається виробляти та (у тому порядку), не розпізнає мову, сформовану граматикою .SаSаSааSаSа | аа

Здається, лише розбирають слова з мови .{а2н | н1}

Я створив такий аналізатор, використовуючи цей генератор парсерів ABNF з правилом виробництва, S = "a" S "a" / "aa"і аналізатор, наприклад, не розпізнає це слово aaaaaa.

Я б очікував, що він використовуватиме виробництво до тих пір, поки конкатенація кінцевих вузлів дерева розбору зліва не починається з 7 -х, а потім піднімається вгору на дерево розбору, вибираючи натомість виробництво поки дерево не схоже це:SаSаaSаа

   S 
 / | \
a  S  a
 / | \
a  S  a
  / \
 a   a

2
Чому, на вашу думку, він не може розібрати це слово?
Yuval Filmus

@Yuval, я думаю, що це слід розібрати, тому я, мабуть, щось пропущую.
meribold

Ага, тепер питання має більше сенсу; дякую за редагування! Якщо те, що ви пишете, є правдою (я не перевіряв) у генераторі, здається, помилка. (Або це не вказано для вашої граматики; я думаю, це малоймовірно, оскільки граматика є елементарною та однозначною.
Рафаель

@Raphael, я знову відредагував це питання (сподіваюся, не змінюючи значення). Мені фактично доручено пояснити, чому такий аналізатор не розпізнає це слово aaaaaa.
meribold

Де ти взяв це дерево. Я не отримую багато від цього генератора аналізаторів ABNF. Дерево, яке ви даєте, не має особливого сенсу. Але рядок aaaaaaмає розбиратися, а ні. Але aaaaрозбирає. Ви, мабуть, праві щодо повноважень 2. Реч має бути помилена. вона розбирає лише aaс S = "aa" / "a" [S] "a". Чи можете ви простежити, що робить аналізатор?
бабу

Відповіді:


6

Це не багато відповіді, але розбір дерев не відповідає нормальним коментарям.

Ваша граматика повинна проаналізувати рядок .a a a a a aSаSа | аааааааа

Але дерево розбору має таку форму:

      S 
     /|\
    / S \
   / /|\ \
  / / S \ \
 / / / \ \ \
a a a   a a a

або якщо ви віддаєте перевагу цій презентації, з терміналами на різних лініях

     S 
   / | \
  a  S  a
   / | \
  a  S  a
    / \
   a   a

Я перевірив, що генератор аналізатора ABNF, здається, не працює, але не знаю, як простежити, що він робить.

Насправді, схоже, переосмислити множину що не є тим, що визначає граматика.{а2н | н1}

Трохи дивно, що такий розроблений сайт навколо помилкового аналізатора, який також використовує абсолютно нецікаву техніку розбору.


Після подальшого огляду на це:

Я думаю, я знайшов одне джерело проблеми. Квадратні дужки означають необов’язковість .

Отже, ваша граматика повинна бути написана S = "a" S "a" / "aa" або S = "a" [S] "a". Тоді, здається, працює правильно.

Але система, очевидно, втрачається при наявності вдвічі одного і того ж правила в різних формах. Я не впевнений, чому.

Я не знайшов сторінки, що пояснювала б ці синтаксичні питання для конкретизації граматики.

Я все ще вважаю це баггі.


1
Ой. Так. Я не знаю, про що я думав, коли писав це дерево розбору. Я відредагую своє запитання і вставте ваше.
meribold

Я знайшов ще один рекурсивний спуск, повернення генераторів парсеров з онлайн демо тут , і він показує таку ж поведінку з цим правилом:S ::= 'a'<S>'a' | 'a''a'
meribold

Він все ще не розбирає aaaaaaпри використанні S = "a" S "a" / "aa", але ви, здається, маєте рацію щодо дужок.
meribold

Я не бачу сенсу досліджувати рекурсивний спуск, зворотний парсер.
бабу

Ви маєте рацію S = "a" S "a" / "aa"... Я тестував занадто швидко, і натиснув на генерувати замість розбору.
бабу

3

s1()SаSаtrues()s2()Sаа

Подумайте про розбір слова aaaaaaще раз. В один момент дерево розбору буде виглядати так:

   S 
 / | \
a  S  a
 / | \
a  S  a    <--
 / | \
a  S  a
  / \
 a   a

s()trueSSаа

   S 
 / | \
a  S  a
  / \
 a   a

Я схильний вважати це питанням моєю реалізацією, а не загальним рекурсивним аналізатором походження в цілому.

#include <iostream>

char* next;    
bool term(char token) {
    if (*next != '\0')
        return *next++ == token;
    else
        return false;
}

bool s();    
bool s1() {
    return term('a') && s() && term('a');
}    
bool s2() {
    return term('a') && term('a');
}    
bool s() {
    auto save = next;
    return s1() or (next = save, s2());
}    

int main(int argc, char* argv[]) {
    next = "aaaaaa";
    if (s() && *next == '\0') {
        std::cout << "match";
    }
    else
        std::cout << "no match";
}

2

Це особливість, а не помилка

Уважно ознайомтеся з тим, коли і де відбувається зворотний трек:

     1.           2.          3.          4.          5.          6.          7.          8.          9.          10.         11.         12.

     S            S           S           S           S           S           S           S           S           S           S           S      
   / | \        / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \
  a  S  a      a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a
                / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       /   \
               a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a     a
                            / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \
                           a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a
                                        / | \       / | \       / | \       / | \       / | \       / | \       / | \       /   \
                                       a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a     a
                                                    / | \       / | \       / | \       / | \       / | \       /   \
                                                   a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a     a
                                                                / | \       / | \       / | \       /   \   
                                                               a  S  a     a  S  a     a  S  a     a     a
                                                                            / | \       /   \
                                                                           a  S  a     a     a



w[] = 'aaaaaa'  //input
l[] = ''        //current tree leafs


 1. tree:   The parser starts with the start symbol S and tries first alternative S->aSa:       Result: w[0]  = l[0]     w = aaaaaa    l = aSa
 |          -- S->aSa works                                                                         | |     | | 
 6. tree:   The parser matches a after a:                                                       Result: w[6]  = l[6]     w = aaaaaa    l = aaaaaaSaaaaaa
 7. tree:   The parser tries S->aSa again but there is no match!                                Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaSaaaaaaa 
 8. tree:   The parser tries S->aa but there is still no match!                                 Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaaaaaaaa
 9. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaaaaaa
10. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaaaa
11. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaa
12. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaa

Важливим моментом тут є те, що аналізатор відступає після позиції, де був знайдений останній відповідний символ. Ось чому воно «стрибає» з дерева 11 з l = aaaaaaaa на 12-е дерево з l = aaaa , використовуючи S -> aa в l [7].


Нарешті знайшов час відредагувати його! ;)
Себас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.