Наведемо текст LL(1)-синтаксичного аналізатора для мови програмування Pascal, зробивши деякі пояснення:
- Синтаксичний аналізатор мови програмування Pascal використовує для виділення лексем з текстового файла функцію pascal_scaner(), яка при кожному звернені до неї виділяє з файла програми нову лексему. Коли сканер досягне кінця файла, то в подальшому EOF передається як нова лексема. Текст виділеної лексеми знаходиться в змінній lexema[], яка є зовнішньою змінною.
- Допоміжна функція index_elem () знаходить індекс (порядковий номер починаючи з нуля) у відповідному масиві терміналів або нетерміналів.
#include <stdio.h>
#include "mystand.h"
/* визначення структури стека синтаксичого аналiзатора */
#define MAX_STACK 200
int STACK[MAX_STACK], POS_STACK=0;
#define NULL_STACK() (POS_STACK? 0: 1)
#define COPY_STACK() (STACK[POS_STACK])
#define PUSH_STACK() (POS_STACK? --POS_STACK:0)
#define DOWN_STACK(c) (POS_STACK < MAX_STACK? STACK[++POS_STACK]=c,1: 0)
extern int pascal_scaner(void); // функція виділення нової лексеми
extern void scaner_close(void); // функція, що закриває вхідний файл
extern char lexema[]; // поточна вхідна лексема
extern int lexema_code; // код виділеної лексеми
extern int lexema_line; // рядок, з якого прочитана лексема
extern int lexema_pos; // позиція лексеми у рядку
extern int index_elem(int *, int, int);
// Зовнішні змінні для синтаксичного аналізатора:
// - таблиця управління LL(1) - синтаксичним аналізатором - TABL_LL1_UPR.
// Кількість рядків таблиці numnet - кількість нетерміналів граматики,
// кількість стовпчиків - (numtrm+1) - кількість терміналів в граматиці
// Допоміжна функція, яка визначає індекс термінала або нетермінала у
// відповідному масиві.
int index_elem(int *net_term, int num, int elem)
{ int i;
for (i=0; i < num; i++) if (*(net_term+i) = = elem) return i;
}
// Лексичний аналiзатор:
// - видiляє лексему в поле lexema,
// - в поле lexema_code заносить код лексеми.
// - аналізатор повертає E-епсилон слово(lexema_code==0), коли досягли ЕOF,
// iнакше код лексеми в полi lexema_code
// В lexema_line знаходиться номер рядка, з якого прочитана лексема.
// В lexema_pos знаходиться позиція в рядку, з якого прочитана лексема.
int ll1_parser_pascal(q,r)
struct node *q;
struct dnode *r;
{ struct node *qw; int i, line0, colomn, ind;
int upr;
/* початковi установки для синтаксичного аналiзатора */
STACK[0]=0; STACK[1]=*(q->pd); POS_STACK=1; ind=0; lexema_code=0;
/* головний цикл работи синтаксичного аналiзатора */
while (! NULL_STACK()) // поки стек не пустий
{ if (!ind) ind=1, pascal_scaner();
// A. Обробка при умовi, що на вершинi стека термiнал
if (COPY_STACK() >= 0)
{ if (COPY_STACK() == lexema_code)
{ ind=0; PUSH_STACK(); continue; }
// можливо короткий if
if (strcmp(NAME_ELEM(COPY_STACK()),"else") == 0)
{ PUSH_STACK(); PUSH_STACK(); continue; } // короткий if
// Синтаксична помилка
printf("Синтаксична помилка: рядок - %5.5i, позицiя -
%3.3i\n",lexema_line,lexema_pos);
printf("Пропущена лексема %s\n",NAME_ELEM(COPY_STACK()));
printf("Вершина стека - %s, вхiдна лексема - %s -
%s\n",NAME_ELEM(COPY_STACK()),lexema,NAME_ELEM(lexema_code));
scaner_close(); return(0);
}
// B. Обробка при умовi, що на вершинi нетермiнал
line0=index_elem(netname,numnet,COPY_STACK());
if (lexema_code) colomn=index_elem(terminal,numtrm,lexema_code);
else colomn=numtrm;
if (upr= *(TABL_LL1_UPR+line0*(numtrm+1)+colomn))
{ PUSH_STACK();
// пошук продукції в списку продукцій
for(qw=q,i=1; i < upr; i++,qw=qw->next);
// запис правої частини продукції в стек
for (i=qw->len-1; i > 0; i--) DOWN_STACK(*(qw->pd+i));
continue;
}
// Синтаксична помилка в програмi
printf("Синтаксична помилка: рядок - %5.5i, позицiя -
%3.3i\n",lexema_line,lexema_pos);
printf("Вершина стека - %s, вхiдна лексема - %s -
%s\n",NAME_ELEM(COPY_STACK()),lexema,NAME_ELEM(lexema_code));
scaner_close(); return(0);
} // кiнець цикла обробки стека
// Стек порожній: перевiримо стан справ на входi
if (! ind) pascal_scaner(); scaner_close();
if (lexema_code == 0) {
printf("\nВ програмi синтаксичних помилок немає\n");return(1);
}
else {
printf("\nЛогiчний кiнець програми знайдено до кiнця вхiдного файла\n");
return(0);
}
} // кiнець програми