LL(1)-синтаксичний аналізатор для мови Pascal

Наведемо текст 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нець програми

Наши рекомендации