Предиктивный синтаксический анализ — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Общая схема построения парсеров с помощью FIRST и FOLLOW)
Строка 5: Строка 5:
 
Пусть <tex>\Gamma</tex> {{---}} LL(1)-грамматика. Построим для нее парсер.
 
Пусть <tex>\Gamma</tex> {{---}} LL(1)-грамматика. Построим для нее парсер.
  
Для каждого нетерминала A : <tex>A \rightarrow \alpha_1 | \alpha_2 | ... | \alpha_k </tex> создадим функцию A() : Node, возвращающую фрагмент дерева разбора, выведенный из нетерминала A.
+
Для каждого нетерминала A : <tex>A \rightarrow \alpha_1 \mid \alpha_2 \mid ... \mid \alpha_k </tex> создадим функцию A() : Node, возвращающую фрагмент дерева разбора, выведенный из нетерминала A.
  
 
Здесь Node {{---}} структура вида:
 
Здесь Node {{---}} структура вида:
Строка 40: Строка 40:
 
         return res
 
         return res
  
{{TODO | t = Примеры псевдокодов для грамматики арифметических выражений}}
+
== Пример ==
 +
Рассмотрим построение парсера на примере грамматики арифметических выражений.
 +
Запишем грамматику.
 +
 
 +
<tex>
 +
E \to T + E \mid T \\
 +
T \to F \times T \mid F \\
 +
F \to n \mid (E)
 +
</tex>
 +
 
 +
Данная грамматика не является LL(1)-грамматикой, так как содержит правое ветвление, от него нужно избавиться перед построением парсера:
 +
 
 +
<tex>
 +
E \to TE' \\
 +
E' \to +TE' \mid \varepsilon \\
 +
T \to FT' \\
 +
T' \to \times FT' \mid \varepsilon \\
 +
F \to n \mid (E)
 +
</tex>
 +
 
 +
Теперь грамматика стала LL(1)-грамматикой, построим для нее множества FIRST и FOLLOW (их построение подробно разобрано [[Построение FIRST и FOLLOW#Пример | здесь]]).
 +
 
 +
{| style="background-color:#CCC;margin:0.5px"
 +
!style="background-color:#EEE"| Правило
 +
!style="background-color:#EEE"| FIRST
 +
!style="background-color:#EEE"| FOLLOW
 +
|-
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>E</tex>
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>\{\ n,\ (\ \} </tex>
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>\{\ \$,\ )\ \} </tex>
 +
|-
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>E'</tex>
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>\{\ +,\ \varepsilon\ \} </tex>
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>\{\ \$,\ )\ \} </tex>
 +
|-
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>T</tex>
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>\{\ n,\ (\ \} </tex>
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>\{\ +,\ \$\ ,\ )\ \}</tex>
 +
|-
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>T'</tex>
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>\{\ \times,\ \varepsilon\ \} </tex>
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>\{\ +,\ \$\ ,\ )\ \}</tex>
 +
|-
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>F</tex>
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>\{\ n,\ (\ \} </tex>
 +
|style="background-color:#FFF;padding:2px 30px"| <tex>\{\ \times, \ +,\ \$\ ,\ )\ \} </tex>
 +
|}
 +
 
 +
 
 +
 
 
{{TODO | t = Картинки примеров разбора чего-нибудь типа 1+2*3}}
 
{{TODO | t = Картинки примеров разбора чего-нибудь типа 1+2*3}}
 
{{TODO | t = Построение таблицы предиктивного анализа}}
 
{{TODO | t = Построение таблицы предиктивного анализа}}

Версия 15:28, 24 мая 2015

Эта статья находится в разработке!

Общая схема построения парсеров с помощью FIRST и FOLLOW

Для LL(1) грамматик возможна автоматическая генерация парсеров, если известны множества FIRST и FOLLOW. Существуют общедоступные генераторы: ANTLR, GNU bison, Yacc.

Пусть [math]\Gamma[/math] — LL(1)-грамматика. Построим для нее парсер.

Для каждого нетерминала A : [math]A \rightarrow \alpha_1 \mid \alpha_2 \mid ... \mid \alpha_k [/math] создадим функцию A() : Node, возвращающую фрагмент дерева разбора, выведенный из нетерминала A.

Здесь Node — структура вида:

   Node
       children : list<Node>
       value : string

Тут картинка про строку.

   A() : Node
       res = Node("A")
       switch (curToken) :
           case : FIRST(\alpha_1) :
               // \alpha_1 = X_1x_2..x_{t_1}
               // X_1 — нетерминал
               Node t = X_1()
               res.addChild(t)
               // x_2 — терминал
               if (curToken != x_2)
                   error("expected x_2")
               res.addChild(new Node("x_2")
               nextToken()
               // x_3 
               ...
               break;
           case FIRST(\alpha_2) :
               // \varepsilon \in FIRST(\alpha_2)
           case FOLLOW(A) :
               ...
               break;
           ...
           default :
               error("unexpected char")
       return res

Пример

Рассмотрим построение парсера на примере грамматики арифметических выражений. Запишем грамматику.

[math] E \to T + E \mid T \\ T \to F \times T \mid F \\ F \to n \mid (E) [/math]

Данная грамматика не является LL(1)-грамматикой, так как содержит правое ветвление, от него нужно избавиться перед построением парсера:

[math] E \to TE' \\ E' \to +TE' \mid \varepsilon \\ T \to FT' \\ T' \to \times FT' \mid \varepsilon \\ F \to n \mid (E) [/math]

Теперь грамматика стала LL(1)-грамматикой, построим для нее множества FIRST и FOLLOW (их построение подробно разобрано здесь).

Правило FIRST FOLLOW
[math]E[/math] [math]\{\ n,\ (\ \} [/math] [math]\{\ \$,\ )\ \} [/math]
[math]E'[/math] [math]\{\ +,\ \varepsilon\ \} [/math] [math]\{\ \$,\ )\ \} [/math]
[math]T[/math] [math]\{\ n,\ (\ \} [/math] [math]\{\ +,\ \$\ ,\ )\ \}[/math]
[math]T'[/math] [math]\{\ \times,\ \varepsilon\ \} [/math] [math]\{\ +,\ \$\ ,\ )\ \}[/math]
[math]F[/math] [math]\{\ n,\ (\ \} [/math] [math]\{\ \times, \ +,\ \$\ ,\ )\ \} [/math]



TODO: Картинки примеров разбора чего-нибудь типа 1+2*3

TODO: Построение таблицы предиктивного анализа