Zadanie 5 (termin oddania: 12 stycznia 2006, godz. 23:59)

Makrem (od angielskiego slowa "macro") nazywamy przyporzadkowanie
nazwie pewnego tekstu, nazywanego trescia makra. Rozwinieciem makra
w tekscie nazywamy zastapienie jego nazwy trescia.
(Uwaga: to definicja uproszczona - czesto spotykamy mechanizmy makr
znacznie bardziej zlozone, niz przedstawiony w tym zadaniu).

Napisz program ktory, wywolany z trzema argumentami bedacymi nazwami
plikow tekstowych, nazywanych dalej odpowiednio plikiem makr, plikiem
danych i plikiem wynikowym, utworzy plik wynikowy kopiujac do niego
zawartosc pliku danych i rozwijajac przy tym makra zdefiniowane w pliku
makr.

W pliku makr zapisane sa kolejno ich definicje, kazda w oddzielnym
wierszu. Kazdy wiersz rozpoczyna sie od nazwy makra, bedacej mala litera.
Reszta wiersza, az do jego konca, jest trescia makra. Koniec wiersza do
tresci makra juz nie nalezy.

W pliku danych uzycie makra oznaczamy pytajnikiem, po ktorym nastepuje
nazwa. Wystapienie dwoch pytajnikow oznacza, ze nie mamy tu do czynienia
z nazwa makra i do pliku wynikowego nalezy wpisac jeden pytajnik.

Uzycie makra moze tez wystapic w tresci (innego) makra. Podczas
rozwijania jednego makra moze sie pojawic potrzeba rozwiniecia innego.

Np. jesli w pliku makra.txt jest:

aAl?x
z?a ?m ?k
mm?x
kkot?x
xa

a w pliku dane.txt:

Czy ?z??
Tak. ?a ?k ?m.

to program wywolany poleceniem:

./zad5 makra.txt dane.txt wynik.txt

powinien utworzyc plik wynik.txt o zawartosci:

Czy Ala ma kota?
Tak. Ala kota ma.

Uwagi:
Mozna zalozyc, ze wiersze w pliku makr nie sa dlugie, a wiec cala
definicje makra mozna wczytac na zmienna typu string. Nie wolno jednak
przyjmowac takiego zalozenia w stosunku do pliku danych i tym bardziej
pliku wynikowego, gdyz w rezultacie rozwiniecia makra mozemy otrzymac
tekst bardzo dlugi.

Program powinien sprawdzac poprawnosc danych. Jedynym warunkiem, ktorego
badac nie trzeba, jest brak cyklu w definicji makr (chodzi o sytuacje,
w ktorej makro korzysta, bezposrednio lub posrednio, z siebie samego).
Program po stwierdzeniu bledu, powinien wypisac na standardowe wyjscie
jeden wiersz ze slowem "BLAD" (bez cudzyslowow i L zamiast L).

Wskazowki:
Liczbe argumentow, ktore program otrzymal w chwili wywolania, daje
bezparametrowa funkcja "paramcount", a ich wartosci funkcja
"paramstr(i)", gdzie "i" jest numerem kolejnym argumentu, liczonym od 1.

W rozwiazaniu zadania pomocna moze sie okazac rekurencja.