[ Pobierz całość w formacie PDF ]
wszystkie pliki dołączone do poprzedniego poziomu makra są zamykane na tym poziomie, i ekspansja makra na
tym poziomie jest natychmiast przerywana.
III.11.7Wywołania zagnieżdżonych i powtarzanych makr.
Ciała makr mogą również zawierać wywołania makr, i ciała tych wywoływanych makr mogą zawierać
wywołania makr, itd.
Jeśli wywołanie makra jest widziane poza ekspansją makra, kompilator natychmiast rozpoczyna pracę z
ekspansją tego makra. W tym celu linie ciała po ekspansji są wstawiane w miejsce wywołania makra w ciele
makra zawierającego to makro, i tak dzieje się tak długo, aż makro całkowicie podlegnie ekspansji. Wtedy
ekspansja makra wywołującego kontynuowana jest z ciałem makra zagnieżdżonego, które jest wewnątrz tego
makra.
Przykład 1: INSIDE MACRO
SUBB A,R3
ENDM
OUTSIDE MACRO
MOV A,#42
INSIDE
MOV R7,A
ENDM
Wewnątrz ciała makra OUTSIDE, wywoływane jest makro INSIDE. Jeśli OUTSIDE
jest wywołane (i tryb listingu jest ustawiony na $GENONLY), otrzymujemy coś
takiego:
Line I Addr Code Source
15+ 1 0000 74 2A MOV A,#42
17+ 2 0002 9B SUBB A,R3
18+ 1 0003 FF MOV R7,A
Od czasu, gdy wywołania makr mogą być zagnieżdżane do dowolnej głębokości (do czasu, gdy dysponujemy
wolną pamięć), poziom ekspansji makra jest pokazany w kolumnie I pliku listingu.
Od czasu, gdy makra i pliki dołączane mogą być zagnieżdżane w sekwencjach arbitralnych na dowolnej
głębokości, poziom zagnieżdżania jest liczony przez wszystkie poziomy makr i plików. Dla lepszej
przejrzystości, znak znajdujący się za globalnym numerem linii to : dla plików dowiązanych oraz + dla makr.
Jeśli makra wywołują siebie same, zwie się je makrami rekurencyjnymi. W takim przypadku muszą występować
kryteria zatrzymania, by uniknąć ciągłego wywoływania makra przez siebie do czasu, gdy kompilator zgłosi
brak pamięci! Tu wyjściem jest kolejny raz kompilacja warunkowa:
Przykład 2: Makro COUNTDOWN definiuje stałą 16bitową od 1 do n w pamięci ROM. n może być
przekazane do makra jako parametr:
COUNTDOWN MACRO DEPTH
IF DEPTH GT 0
DW DEPTH
COUNTDOWN %DEPTH1
ENDIF
ENDM
Jeśli COUNTDOWN jest wywoływany tak
COUNTDOWN 7
wynik jest następujący (w trybie listingu $GENONLY/$CONDONLY):
Line I Addr Code Source
16+ 1 0000 00 07 DW 7
19+ 2 0002 00 06 DW 6
22+ 3 0004 00 05 DW 5
25+ 4 0006 00 04 DW 4
28+ 5 0008 00 03 DW 3
31+ 6 000A 00 02 DW 2
34+ 7 000C 00 01 DW 1
Po ciemnych wiekach , gdy osiadł kurz i słońce przebiło się przez mrok, nauka komputerowa odkryła metodę
programowania rekurencyjnego. Nie było wątpliwości, że to wyło ROZWIZANIE!
Wtedy naukowcy komputerowi zaczęli wyjaśniać to studentom. Ale wydawało się, że studenci nie rozumieli
tego. Zawsze wyjaśniali, że obliczanie rekurencyjne n! jest głupim przykładem. Wszyscy naukowcy poczuli, że
wciąż im czegoś brakowało. Po kolejnych 10 latach trudnych poszukiwań, znalezli również PROBLEM:
Przykład 3: Wieże Hanoi
Są trzy pionowe kijki na stole. Na kijku 1 jest n dysków o różnej średnicy z otworem w
środku, najmniejszy dysk na górze, największy na dole.
Patyk nr1 Patyk nr 2 Patyk nr 3
| | |
Dysk 1 ==|== | |
Dysk 2 ===|=== | |
Dysk n ====|==== | |
| | |
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Problem polega na przeniesieniu wieży dysków z kijka nr 1 na kijek nr 2 przy pomocy najmniejszej
liczby ruchów. Tylko najwyżej położony dysk może być ruszony za jednym razem i żaden dysk nie
może leżeć na mniejszym dysku. Kijek trzeci może zostać użyty jako początkowy. To jest
ROZWIZANIE z użyciem makr w ASEM51:
;Wieże Hanoi
$GENONLY CONDONLY
DISCS EQU 3 ;ilość dysków
HANOI MACRO n, SOURCE, DESTINATION, SCRATCH
IF n > 0
HANOI %(n1), SOURCE, SCRATCH, DESTINATOR
;rusz najwyżej położony dysk z kijka &SOURCE na kijek &DESTINATION
HANOI %(n1), SCRATCH, DESTINATION, SOURCE
ENDIF
ENDM
HANOI DISCS, 1, 2, 3
END
Makro rekurencyjne HANOI generuje instrukcjÄ™ dla PROBLEMU, gdzie instrukcje pojawiajÄ… siÄ™ jako
linie komentarza w liniach pliku listingu. Symbol DISCS musi być ustawiony do żądanej liczby
dysków. Jeśli HANOI jest wywołane następująco:
HANOI 3, 1, 2, 3
następująca instrukcja jest generowana:
27+ 3 ; rusz najwyżej położony dysk z kijka 1 na kijek 2
35+ 2 ; rusz najwyżej położony dysk z kijka 1 na kijek 3
44+ 3 ; rusz najwyżej położony dysk z kijka 2 na kijek 3
53+ 1 ; rusz najwyżej położony dysk z kijka 1 na kijek 2
64+ 3 ; rusz najwyżej położony dysk z kijka 3 na kijek 1
72+ 2 ; rusz najwyżej położony dysk z kijka 3 na kijek 2
81+ 3 ; rusz najwyżej położony dysk z kijka 1 na kijek 2
Kontrolki GENONLY i CONDONLY zapewniają, że tabela nie będzie zawierać całego wywołania
makra i konstrukcji IF.
wiczenie 1:
Zmodyfikuj makro HANOI tak, by generowało tabelę ruchów w pamięci ROM, co mogło by być
używane jako wejście dla ramienia robota kontrolowanego przez 8051, które rzeczywiście gra w grę
z 3 rzeczywistymi kijkami i realnymi n dyskami.
wiczenie 2: n
Udowodnij, że minimalna ilość ruchów to 2 1. ;)
III.11.8Definicje makr zagnieżdżonych
Ciała makra mogą także zawierać dalsze makrodefinicje. Jednakże takie zagnieżdżone makrodefinicje nie są
prawidłowe dopóki makro, które je zawiera nie ulegnie ekspansji. Oznacza to, że makro musi zostać wywołane
zanim możliwe będzie wywołanie zagnieżdżonego makra.
Przykład 1: Makro, które może zostać użyte do definiowania makr z nazwami arbitralnymi, może
wyglądać w następujący sposób:
DEFINE MACRO MACNAME
MACNAME MACRO
DB 'I am the macro &MACNAME.'
ENDM
ENDM
By nie przeładować przykładu przez jak to się robi , :)
makro zagnieżdżone przedstawia się tylko delikatnie
z pomocą odpowiedniego znaku w pamięci ROM. Wywołanie
DEFINE Obiwan
zdefiniuje makro
Obiwan MACRO
DB 'I am the macro Obiwan.'
ENDM
a wywołanie
DEFINE Skywalker
zdefiniuje makro:
Skywalker MACRO
DB 'I am the macro Skywalker.'
ENDM
Przykład 2: Poniższe makro ma wstawiać w od zmienną ilość instrukcji NOP. W tym celu makro z
zagnieżdżonymi blokami REPT wydaje się najlepszym rozwiązaniem:
REPEAT MACRO NOPS
REPT NOPS
NOP
ENDM
ENDM
Wywołanie
REPEAT 4
w rezultacie stworzy coÅ› takiego:
Line I Addr Code Source
9+ 1 N 0004 REPT 4
10+ 1 NOP
11+ 1 ENDM
12+ 2 0000 00 NOP
13+ 2 0001 00 NOP
14+ 2 0002 00 NOP
15+ 2 0003 00 NOP
III.11.9Reprezentacja w pliku "List File"
Czasami ekspansja makra ma tendencję do generowania o wiele więcej linii listingu niż kodu. Listować czy nie
listować oto jest pytanie! Wymagania by osiągnąć lepszy pogląd na całość lub mieć więcej detali mogą być
różne w różnych fazach tworzenia programu lub w innych sekcjach programu. By zawsze mieć najlepsze
rezultaty, kilka generalnych kontrolek zostało wprowadzonych, które oddziałują na reprezentację ekspansji
makra oraz konstrukcji IFxx w pliku listingu (zobacz rozdział III.8 Kontrolki Asemblera ):
Kontrolka Typ Domyślna Skrót Znaczenie
$GEN G $GEN $GE listowanie wywołań makr i linii ekspansji
$NOGEN G $NOGE listowanie tylko wywołań makr
$GENONLY G $GO listowanie tylko linii ekspansji
$COND G $COND listowanie pełnej konstrukcji IFxx.. ENDIF
$NOCOND G nie listuj linii dla nieprawdziwych warunków
$CONDONLY G listuj tylko linie kompilowane
[ Pobierz całość w formacie PDF ]