5 WSKAŹNIKI I TABLICE__-— ---
konstrukcja *pfa[] zostanie rozpoznana jako deklarator, a zatem (*pfa[ ]) też jest bezpośrednim deklaratorem. Na koniec, konstrukcja (*pfa[ ]) () jest bezpośrednim de-klaratorem, a zatem jest deklaratorem. Ten rozbiór gramatyczny możemy także zilustrować graficznie za pomocą drzewa wywodu (w którym deklarator skróciliśmy do deki, a bezpośredni-deklarator do bezp-dekl):
( * pfa [ ] ) ()
„Sercem” programu dcl jest para funkcji, dcl i dirdcl, które dokonują rozbioru gramatycznego deklaracji według podanej składni (dcl odpowiada jednostce składniowej deklarator, a dirdcl - jednostce składniowej bezpośredni-deklarator). Składnię zdefiniowano rekurencyjnie, zatem obie funkcje także wywołują się rekurencyjnie po rozpoznaniu fragmentu deklaracji. Taki program jest nazywany rekurencyjnie zstępującym analizatorem składniowym.
/* dcl: analiza składniowa deklaratora */
void dcl (void)
int ns;
for (ns = 0; gettoken() == V;) /* zlicza *-i */ ns++;
dirdcl ();
while (ns-- > 0)
strcat(out, ” wskaźnik do”);
5.12 SKOMPLIKOWANE DEKLARACJE ______
—power^d—by
Mi siol
/* dirdcl: analiza składniowa bezpośredniego deklaratora */ void dirdcl (void)
int type;
if (tokentype == ’(’) { /* (deklarator) */
dcl ();
if (tokentype != ')’)
printffbłąd: brak nawiasu )\n”);
} else if (tokentype == NAME ) /* nazwa zmiennej */ strcpy(name, token);
else
printf(”błąd: spodziewana nazwa lub (deklarator)\nu); while ((tyf>e = gettoken()) == PARENS || type == BRACKETS) if (type == PARENS) /* para nawiasów () */
strcat(out, ” funkcja zwracająca"); else { /* para nawiasów [ ] */
strcat(out, ” tablica”);
strcat(out, token); /* ew. rozmiar */
strcat(out, ” o elementach”);
Ponieważ te programy z zamierzenia są ilustracyjne, a nie „kuloodporne”, trzeba było poważnie ograniczyć możliwości programu dci. Obsługuje on jedynie proste typy danych, jak char czy int. Nie zajmuje się typami argumentów funkcji ani kwalifikatorami jak np. const. Fałszywe odstępy wprawiają go w zakłopotanie. Program dcl nie szuka błędów zbyt dokładnie, więc niepoprawne deklaracje także wprawiają go w zakłopotanie. Takie udoskonalenia pozostawiono do opracowania jako ćwiczenia.
A oto zmienne globalne i główna procedura programu dcl:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXTOKEN 100
enum { NAME, PARENS, BRACKETS };
void dcl(void); void dirdcl(void);
169