<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=178.71.143.38&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=178.71.143.38&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/178.71.143.38"/>
		<updated>2026-04-22T23:50:35Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D0%B4%D0%B8%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B9_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7&amp;diff=46917</id>
		<title>Предиктивный синтаксический анализ</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D0%B4%D0%B8%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B9_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7&amp;diff=46917"/>
				<updated>2015-05-25T13:52:03Z</updated>
		
		<summary type="html">&lt;p&gt;178.71.143.38: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Для [[LL(k)-грамматики, множества FIRST и FOLLOW | LL(1)-грамматик]] возможна автоматическая генерация парсеров, если известны множества &amp;lt;tex&amp;gt;\mathrm{FIRST}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathrm{FOLLOW}&amp;lt;/tex&amp;gt;. Существуют общедоступные генераторы: ANTLR&amp;lt;ref&amp;gt;[http://www.antlr.org/ ANTLR {{---}} Parser generator]&amp;lt;/ref&amp;gt;, Bison&amp;lt;ref&amp;gt;[http://www.gnu.org/software/bison/ Bison {{---}} GNU Project]&amp;lt;/ref&amp;gt;, Yacc&amp;lt;ref&amp;gt;[http://dinosaur.compilertools.net/ Lex &amp;amp; Yacc {{---}} A Lexical Analyzer Generator and Yet Another Compiler-Compiler]&amp;lt;/ref&amp;gt;, Happy&amp;lt;ref&amp;gt;[https://www.haskell.org/happy/ Happy {{---}} The Parser Generator for Haskell]&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Общая схема построения рекурсивных парсеров с помощью FIRST и FOLLOW ==&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;\Gamma =\langle \Sigma, N, S, P \rangle&amp;lt;/tex&amp;gt; {{---}} LL(1)-грамматика. Построим для нее парсер.&lt;br /&gt;
&lt;br /&gt;
Для каждого нетерминала &amp;lt;tex&amp;gt;A : A \rightarrow \alpha_1 \mid \alpha_2 \mid \ldots \mid \alpha_k &amp;lt;/tex&amp;gt; создадим функцию &amp;lt;tex&amp;gt; \mathtt{A}() : \mathtt{Node} &amp;lt;/tex&amp;gt;, возвращающую фрагмент [[Контекстно-свободные грамматики, вывод, лево- и правосторонний вывод, дерево разбора#Дерево разбора | дерева разбора]], выведенный из нетерминала &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;tex&amp;gt;\mathtt{Node}&amp;lt;/tex&amp;gt; {{---}} структура следующего вида:&lt;br /&gt;
 '''struct''' Node&lt;br /&gt;
     children : '''list&amp;lt;Node&amp;gt;'''&lt;br /&gt;
     value : '''string'''          &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// имя нетерминала или текст терминала&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''function''' addChild('''Node''') &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// функция, подвешивающая поддерево к данному узлу&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Каждый момент времени парсер работает с определённым '''токеном''' (англ. ''token'') входного слова &amp;lt;tex&amp;gt;s&amp;lt;/tex&amp;gt;. Токен {{---}} один или несколько терминалов, объединяемые по смыслу. Примерами токенов могут выступать следующие лексические единицы:&lt;br /&gt;
* произвольный символ &amp;lt;tex&amp;gt; c &amp;lt;/tex&amp;gt;,&lt;br /&gt;
* целое слово, например &amp;lt;tex&amp;gt; public &amp;lt;/tex&amp;gt;,&lt;br /&gt;
* число со знаком, обозначаемое далее для краткости как &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;.&lt;br /&gt;
В общем случае, токеном может являться любое слово, удовлетворяющее произвольному [[Регулярные языки: два определения и их эквивалентность | регулярному выражению]].&lt;br /&gt;
&lt;br /&gt;
[[Файл:string_token.png|300px]]&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; обозначает маркер конца строки.&lt;br /&gt;
&lt;br /&gt;
В псевдокоде используются следующие обозначения:&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathtt{curToken}&amp;lt;/tex&amp;gt; {{---}} текущий токен строки,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathtt{nextToken()}&amp;lt;/tex&amp;gt; {{---}} функция, записывающая в &amp;lt;tex&amp;gt;\mathtt{curToken}&amp;lt;/tex&amp;gt; следующий за ним токен.&lt;br /&gt;
&lt;br /&gt;
Тогда шаблон функции рекурсивного парсера для нетерминала &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; имеет вид:&lt;br /&gt;
&lt;br /&gt;
 A() : '''Node'''&lt;br /&gt;
     Node res = Node(&amp;quot;A&amp;quot;)&lt;br /&gt;
     '''switch''' (curToken) : &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// принимаем решение в зависимости от текущего токена строки&amp;lt;/font&amp;gt;&lt;br /&gt;
         '''case''' &amp;lt;tex&amp;gt;\mathrm{FIRST}(\alpha_1) \cup (\mathrm{FOLLOW}(A)\ \mathrm{if}\ \varepsilon \in \mathrm{FIRST}(\alpha_1))&amp;lt;/tex&amp;gt; :&lt;br /&gt;
             &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// &amp;lt;tex&amp;gt;\alpha_1 = X_1X_2 \ldots X_{t}&amp;lt;/tex&amp;gt; &amp;lt;/font&amp;gt;&lt;br /&gt;
             '''for''' i = 1 .. t&lt;br /&gt;
                 '''if''' &amp;lt;tex&amp;gt; X_i &amp;lt;/tex&amp;gt; {{---}} терминал&lt;br /&gt;
                     consume(&amp;lt;tex&amp;gt;X_i&amp;lt;/tex&amp;gt;)&lt;br /&gt;
                     res.addChild(Node(&amp;quot;&amp;lt;tex&amp;gt;X_i&amp;lt;/tex&amp;gt;&amp;quot;)&lt;br /&gt;
                 '''else''' &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// &amp;lt;tex&amp;gt;X_i&amp;lt;/tex&amp;gt; {{---}} нетерминал, нужно вызвать соответствующую ему функцию рекурсивного парсера &amp;lt;/font&amp;gt;&lt;br /&gt;
                     Node t = &amp;lt;tex&amp;gt;X_i()&amp;lt;/tex&amp;gt;&lt;br /&gt;
                     res.addChild(t)&lt;br /&gt;
             '''break'''&lt;br /&gt;
         '''case''' &amp;lt;tex&amp;gt;\mathrm{FIRST}(\alpha_2) \cup (\mathrm{FOLLOW}(A)\ \mathrm{if}\ \varepsilon \in \mathrm{FIRST}(\alpha_2))&amp;lt;/tex&amp;gt; : &lt;br /&gt;
             &amp;lt;tex&amp;gt;\ldots&amp;lt;/tex&amp;gt;&lt;br /&gt;
             '''break'''&lt;br /&gt;
         &amp;lt;tex&amp;gt;\ldots&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''default''' :&lt;br /&gt;
             &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;error&amp;lt;/font&amp;gt;(&amp;quot;unexpected char&amp;quot;)&lt;br /&gt;
     '''return''' res&lt;br /&gt;
&lt;br /&gt;
 '''function''' consume(c: '''char''') &lt;br /&gt;
     '''if''' curToken != c&lt;br /&gt;
         &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;error&amp;lt;/font&amp;gt;(&amp;quot;expected &amp;quot; + c)&lt;br /&gt;
     nextToken()&lt;br /&gt;
&lt;br /&gt;
Такой парсер не только разбирает строку, но и находит ошибки в неудовлетворяющих грамматике выражениях.&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
Рассмотрим построение парсера на примере LL(1)-грамматики арифметических выражений, которая уже была разобрана [[Построение FIRST и FOLLOW#Пример | ранее]]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; &lt;br /&gt;
E \to TE' \\&lt;br /&gt;
E' \to +TE' \mid \varepsilon \\&lt;br /&gt;
T \to FT' \\&lt;br /&gt;
T' \to * FT' \mid \varepsilon \\&lt;br /&gt;
F \to n \mid (E)&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Напомним, что множества &amp;lt;tex&amp;gt;\mathrm{FIRST}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathrm{FOLLOW}&amp;lt;/tex&amp;gt; для неё выглядят так:&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;background-color:#CCC;margin:0.5px&amp;quot;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Правило&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| FIRST&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| FOLLOW&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;\{\ n,\ (\ \} &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;\{\ \$,\ )\ \} &amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;E'&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;\{\ +,\ \varepsilon\ \} &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;\{\ \$,\ )\ \} &amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;\{\ n,\ (\ \} &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;\{\ +,\ \$\ ,\ )\ \}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;T'&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;\{\ *,\ \varepsilon\ \} &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;\{\ +,\ \$\ ,\ )\ \}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;\{\ n,\ (\ \} &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &amp;lt;tex&amp;gt;\{\ *, \ +,\ \$\ ,\ )\ \} &amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Псевдокоды ===&lt;br /&gt;
Построим функции обработки некоторых нетерминалов, используя описанный выше шаблон:&lt;br /&gt;
&lt;br /&gt;
 E() : '''Node'''&lt;br /&gt;
     Node res = Node(&amp;quot;E&amp;quot;)&lt;br /&gt;
     '''switch''' (curToken)&lt;br /&gt;
         '''case''' n, '('  :&lt;br /&gt;
             res.addChild(T())&lt;br /&gt;
             res.addChild(E'())&lt;br /&gt;
             '''break'''&lt;br /&gt;
         '''default''' :&lt;br /&gt;
             &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;error&amp;lt;/font&amp;gt;(&amp;quot;unexpected char&amp;quot;)&lt;br /&gt;
     '''return''' res&lt;br /&gt;
&lt;br /&gt;
 E'() : '''Node'''&lt;br /&gt;
     Node res = Node(&amp;quot;E'&amp;quot;)&lt;br /&gt;
     '''switch''' (curToken) &lt;br /&gt;
         '''case''' '+' :&lt;br /&gt;
             consume('+')&lt;br /&gt;
             res.addChild(Node(&amp;quot;+&amp;quot;))&lt;br /&gt;
             res.addChild(T())&lt;br /&gt;
             res.addChild(E'())&lt;br /&gt;
             '''break'''&lt;br /&gt;
         '''case''' '$', ')' :&lt;br /&gt;
             '''break'''&lt;br /&gt;
         '''default''' :&lt;br /&gt;
             &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;error&amp;lt;/font&amp;gt;(&amp;quot;unexpected char&amp;quot;)&lt;br /&gt;
      '''return''' res&lt;br /&gt;
&lt;br /&gt;
 F() : '''Node'''&lt;br /&gt;
     Node res = Node(&amp;quot;F&amp;quot;)&lt;br /&gt;
     '''switch''' (curToken)&lt;br /&gt;
         '''case''' n :&lt;br /&gt;
             consume(n)&lt;br /&gt;
             res.addChild(Node(curToken)) &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// &amp;lt;tex&amp;gt;\mathtt{curToken}&amp;lt;/tex&amp;gt; подпадает под шаблон &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, поэтому запишем его в &amp;lt;tex&amp;gt;\mathtt{value}&amp;lt;/tex&amp;gt; вершины&amp;lt;/font&amp;gt;&lt;br /&gt;
             '''break'''&lt;br /&gt;
         '''case''' '(' :&lt;br /&gt;
             consume('(')&lt;br /&gt;
             res.addChild(Node(&amp;quot;(&amp;quot;))&lt;br /&gt;
             res.addChild(E())&lt;br /&gt;
             consume(')')&lt;br /&gt;
             res.addChild(Node(&amp;quot;)&amp;quot;))&lt;br /&gt;
         '''default''' :&lt;br /&gt;
             &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;error&amp;lt;/font&amp;gt;(&amp;quot;unexpected char&amp;quot;)&lt;br /&gt;
     '''return''' res&lt;br /&gt;
&lt;br /&gt;
Функции для &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;T'&amp;lt;/tex&amp;gt; строятся аналогично.&lt;br /&gt;
&lt;br /&gt;
=== Дерево разбора ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим дерево разбора для выражения &amp;lt;tex&amp;gt;(1 + 2) * 3&amp;lt;/tex&amp;gt; и несколько первых шагов алгоритма рекурсивного разбора. Сначала вызывается функция стартового нетерминала грамматики, то есть &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt;. Так как первым токеном является '(', то будет использовано первое правило разбора &amp;lt;tex&amp;gt;TE'&amp;lt;/tex&amp;gt;. Поэтому к вершине с меткой &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt; добавятся два ребёнка: &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;E'&amp;lt;/tex&amp;gt;, а рекурсивный разборщик перейдёт к нетерминалу &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;. curToken по-прежнему равен '(', поэтому в &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt; сработает второй case, первым ребёнком добавится '(', curToken станет равен &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;, а разборщик перейдёт к нетерминалу &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt;. После того как выражение после '(', которое выводится из &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt;, будет полностью разобрано, функция рекурсивного разбора для &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt; добавит ')' последним сыном к этому нетерминалу. &lt;br /&gt;
&lt;br /&gt;
Продолжая в том же духе, мы построим всё дерево разбора данного выражения.&lt;br /&gt;
&lt;br /&gt;
[[Файл:parse_ex1.png|400px|thumb|center|Дерево разбора выражения &amp;lt;tex&amp;gt;(1 + 2) * 3&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
== Нерекурсивный нисходящий парсер ==&lt;br /&gt;
&lt;br /&gt;
[[Файл:Parse_table.png|400px|right]]&lt;br /&gt;
&lt;br /&gt;
Рекурсивные разборщики можно генерировать автоматически, зная множества &amp;lt;tex&amp;gt;\mathrm{FIRST}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathrm{FOLLOW}&amp;lt;/tex&amp;gt;, так как они имеют достаточно прозрачный шаблон построения. Альтернативным способом осуществления нисходящего синтаксического анализа является построение нерекурсивного нисходящего парсера. Его можно построить с помощью явного использования [[Стек | стека]] (вместо неявного при рекурсивных вызовах). Такой анализатор имитирует &lt;br /&gt;
[[Контекстно-свободные грамматики, вывод, лево- и правосторонний вывод, дерево разбора#Лево- и правосторонний вывод слова | левое порождение]].  &lt;br /&gt;
&lt;br /&gt;
Стек нерекурсивного предиктивного синтаксического анализатора содержит последовательность терминалов и нетерминалов и таблицу синтаксического анализа. На стеке располагается последовательность символов грамматики с маркером конца разбора &amp;lt;tex&amp;gt;\perp&amp;lt;/tex&amp;gt; на дне. В начале процесса анализа строки стек содержит стартовый нетерминал грамматики непосредственно над символом &amp;lt;tex&amp;gt;\perp&amp;lt;/tex&amp;gt;. Таблица синтаксического анализа представляет собой двухмерный массив &amp;lt;tex&amp;gt;\mathcal{M}[A, c]&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; {{---}} нетерминал или &amp;lt;tex&amp;gt;\perp&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt; c &amp;lt;/tex&amp;gt; {{---}} токен или символ конца строки &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Нерекурсивный синтаксический анализатор смотрит на текущий токен &amp;lt;tex&amp;gt; c &amp;lt;/tex&amp;gt; входного слова и на символ на вершине стека &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;, а затем принимает решение в зависимости от одного из возникающих ниже случаев:&lt;br /&gt;
* если &amp;lt;tex&amp;gt;A\ =\ \perp\ \land\ c\ =\ \$&amp;lt;/tex&amp;gt;, то синтаксический анализатор прекращает работу, так как разбор строки завершён,&lt;br /&gt;
* eсли &amp;lt;tex&amp;gt;A = c&amp;lt;/tex&amp;gt;, то синтаксический анализатор снимает со стека токен &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; и перемещает указатель текущего токена ленты к следующему токену (то есть вызывает &amp;lt;tex&amp;gt;\mathtt{nextToken}&amp;lt;/tex&amp;gt;), таким образом, происходит выброс символа &amp;lt;tex&amp;gt; c &amp;lt;/tex&amp;gt; со стека,&lt;br /&gt;
* eсли &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; является нетерминалом, то программа рассматривает запись &amp;lt;tex&amp;gt;\mathcal{M}[A,c]&amp;lt;/tex&amp;gt; таблицы разбора &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt;. Эта запись представляет собой либо правило грамматики вида &amp;lt;tex&amp;gt;A \to \alpha_i,\ \alpha_i = X_1 X_2 \ldots X_t&amp;lt;/tex&amp;gt;, и тогда &amp;lt;tex&amp;gt;\mathcal{M}[A,c]&amp;lt;/tex&amp;gt; содержит номер &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; данного правила, либо запись об ошибке, и тогда &amp;lt;tex&amp;gt;\mathcal{M}[A,c] = \varnothing&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;\mathcal{M}[A,c] \neq \varnothing&amp;lt;/tex&amp;gt;, то синтаксический анализатор замещает на стеке нетерминал &amp;lt;tex&amp;gt; A &amp;lt;/tex&amp;gt; правой частью правила с номером &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;, помещая символы правила на стек в обратном порядке,&lt;br /&gt;
* во всех остальных случаях парсер выдаёт сообщение об ошибке.&lt;br /&gt;
&lt;br /&gt;
Рассмотренные случаи отображены на картинке справа, где блок &amp;lt;tex&amp;gt; N &amp;lt;/tex&amp;gt; отвечает нетерминалам грамматики. Из картинки видно, что вместо рассмотрения всех случаев в коде достаточно просто создать таблицу &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt; таким образом, чтобы она учитывала все случаи, что упростит код.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&lt;br /&gt;
Здесь по-прежнему &amp;lt;tex&amp;gt;\mathtt{curToken}&amp;lt;/tex&amp;gt; обозначает текущий токен строки, а &amp;lt;tex&amp;gt;\mathtt{nextToken}&amp;lt;/tex&amp;gt; передвигает указатель на следующий токен.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code style = &amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
 '''function''' nonRecursiveParser():&lt;br /&gt;
     st : '''Stack'''&lt;br /&gt;
     st.push(&amp;lt;tex&amp;gt;\perp&amp;lt;/tex&amp;gt;)&lt;br /&gt;
     st.push(&amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;) &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// здесь &amp;lt;tex&amp;gt; S &amp;lt;/tex&amp;gt; {{---}} стартовый нетерминал грамматики&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''while''' s.top() &amp;lt;tex&amp;gt;\neq\ \perp&amp;lt;/tex&amp;gt; &lt;br /&gt;
         A = st.top()&lt;br /&gt;
         '''if''' &amp;lt;tex&amp;gt;\mathcal{M}[A,\ curToken]\ ==\ \mathrm{ok}&amp;lt;/tex&amp;gt; &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// &amp;lt;tex&amp;gt; A\ ==\ \perp &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{curToken}\ ==\ \$&amp;lt;/tex&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
             '''break''' &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// разбор строки завершён&amp;lt;/font&amp;gt;&lt;br /&gt;
         '''else if''' &amp;lt;tex&amp;gt;\mathcal{M}[A,\ curToken]\ ==\ \nearrow&amp;lt;/tex&amp;gt; &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// выброс&amp;lt;/font&amp;gt;&lt;br /&gt;
             nextToken()&lt;br /&gt;
             st.pop()&lt;br /&gt;
             вывести в выходной поток нетерминал, отвечающий &amp;lt;tex&amp;gt;\mathtt{curToken}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''else if''' &amp;lt;tex&amp;gt;\mathcal{M}[A,\ curToken]&amp;lt;/tex&amp;gt; {{---}} номер правила &amp;lt;tex&amp;gt;A \to \alpha_i,\ \alpha_i = X_1 X_2 \ldots X_t&amp;lt;/tex&amp;gt;&lt;br /&gt;
             st.pop()&lt;br /&gt;
             '''for''' k = t '''downto''' 1&lt;br /&gt;
                 st.push(&amp;lt;tex&amp;gt;X_k&amp;lt;/tex&amp;gt;)    &lt;br /&gt;
             вывести в выходной поток терминал, отвечающий &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''else'''&lt;br /&gt;
             &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;error&amp;lt;/font&amp;gt;(&amp;quot;unexpected symbol&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Пример ===&lt;br /&gt;
&lt;br /&gt;
Рассмотрим пример работы нерекурсивного парсера на всё той же грамматике арифметических выражений. Для начала пронумеруем все правила:&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;background-color:#CCC;margin:0.5px&amp;quot;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Номер&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Правило&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| &amp;lt;tex&amp;gt;E \to TE'&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| &amp;lt;tex&amp;gt;E' \to +TE'&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| &amp;lt;tex&amp;gt;E' \to \varepsilon&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| &amp;lt;tex&amp;gt;T \to FT'&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| &amp;lt;tex&amp;gt;T' \to * FT'&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| &amp;lt;tex&amp;gt;T' \to \varepsilon&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| &amp;lt;tex&amp;gt;F \to n&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;8&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 10px&amp;quot;| &amp;lt;tex&amp;gt;F \to (E)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Теперь можно построить часть таблицы &amp;lt;tex&amp;gt;\mathcal{M}&amp;lt;/tex&amp;gt;, содержащей отвечающие нетерминалам строки. Её построение легко осуществить, если известны &amp;lt;tex&amp;gt;\mathrm{FIRST}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathrm{FOLLOW}&amp;lt;/tex&amp;gt;. По этим множествам можно понять, какое правило использовать для данного нетерминала при текущем токене.&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;background-color:#CCC;margin:0.5px&amp;quot;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| &lt;br /&gt;
!style=&amp;quot;background-color:#EEE;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;(&amp;lt;/tex&amp;gt;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;)&amp;lt;/tex&amp;gt;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;+&amp;lt;/tex&amp;gt;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;*&amp;lt;/tex&amp;gt;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;1 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;1 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;E'&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;3 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;2 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;3 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;4 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;4 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;T'&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;6 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;6 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;5 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;6 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;F&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;7 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;8 &amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;\perp&amp;lt;/tex&amp;gt;&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px;text-align:center;&amp;quot;| &amp;lt;tex&amp;gt;\mathrm{ok}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На картинке ниже показаны состояния стека на нескольких первых итерациях цикла и указатель на текущий токен.&lt;br /&gt;
&lt;br /&gt;
[[Файл:Parse_stack.png|500px]]&lt;br /&gt;
&lt;br /&gt;
== Примечания ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* Альфред Ахо, Рави Сети, Джеффри Ульман. Компиляторы. Принципы, технологии, инструменты. Издательство Вильямс. Второе издание. 2008. Стр. 288 {{---}} 294.&lt;br /&gt;
&lt;br /&gt;
[[Категория: Методы трансляции]]&lt;br /&gt;
[[Категория: Нисходящий разбор]]&lt;/div&gt;</summary>
		<author><name>178.71.143.38</name></author>	</entry>

	</feed>