You are on page 1of 56

9/!Qumf!j!lpotusvldkf!

tufsvkdf

22:

Jak ju wczeniej powiedzielimy, w skad programw napisanych w jzyku AutoLISP


wchodz funkcje. Wewntrz funkcji wystpuj instrukcje. O sile jzyka w duej mierze
decyduj mechanizmy suce do specyfikacji kolejnoci wykonywania instrukcji.
Wszystkie nowoczesne jzyki programowania maj po kilka struktur sterujcych, ktre
pozwalaj, aby pewne fragmenty programu byy wykonywane tylko jeden raz lub
wielokrotnie w zalenoci od spenienia lub niespenienia jakiego warunku. Inaczej
mwic od prawdziwoci lub faszywoci jakiego wyraenia. Poniewa temat prawda
fasz w AutoLISPie zosta ju omwiony wczeniej (przy okazji omawiania
operatorw), zostan teraz omwione po kolei poszczeglne konstrukcje sterujce
stosowane w jzyku AutoLISP.
Programy omwione w tym rozdziale
PROG_012.LSP
Przykad instrukcji warunkowej if.
PROG_013.LSP
Przykad instrukcji warunkowej if z zastosowaniem instrukcji zoonej.
PROG_014.LSP
Przykad instrukcji warunkowej if.
Obliczenie pierwiastkw rwnania kwadratowego wersja 1.
PROG_015.LSP
Przykad instrukcji warunkowej if.
Obliczenie pierwiastkw rwnania kwadratowego wersja 2.
PROG_016.LSP
Przykad uycia instrukcji while wersja 1.

231

BvupMJTQ!!qsbluzd{oz!lvst
PROG_017.LSP
Przykad uycia instrukcji while wersja 2.
PROG_018.LSP
Przykad uycia instrukcji while.
Obliczenie i wypisanie kwadratw liczb cakowitych od 1 do 10.
PROG_019.LSP
Przykad zagniedonej instrukcji while.
Wypisanie liczb od 1 do 100 w 10 rzdach po 10 kolumn.
PROG_020.LSP
Przykad uycia instrukcji cond wersja 1.
PROG_021.LSP
Przykad uycia instrukcji cond wersja 2.
PROG_022.LSP
Przykad uycia instrukcji cond.
Obliczenie pierwiastkw rwnania kwadratowego.
PROG_023.LSP
Przykad uycia instrukcji repeat.
Obliczenie i wypisanie kwadratw liczb cakowitych od 1 do 100.
PROG_024.LSP
Przykad uycia zagniedonych instrukcji repeat.
Wypisanie liczb od 1 do 100 w 10 rzdach po 10 kolumn.
PROG_025.LSP
Realizacja ptli FOR w AutoLISPie.
PROG_026.LSP
Uycie instrukcji FOR przykad 1.
PROG_027.LSP
Uycie instrukcji FOR przykad 2.
PROG_028.LSP
Uycie instrukcji FOR przykad 3.
Tworzenie listy oraz wywietlanie jej zawartoci.
PROG_029.LSP
Uycie instrukcji FOR przykad 4.
Obliczenie i wypisanie kwadratw liczb cakowitych od 1 do 10.
PROG_030.LSP
Uycie zagniedonych instrukcji FOR.
Wypisanie liczb od 1 do 100 w 10 rzdach po 10 kolumn.

9/!Qumf!j!lpotusvldkf!tufsvkdf

232

PROG_031.LSP
Realizacja ptli DO_WHILE w AutoLISPie.
PROG_032.LSP
Uycie instrukcji DO_WHILE.
Obliczenie i wypisanie kwadratw liczb cakowitych od 1 do 10.

Czsto zdarza si, e, w zalenoci od sytuacji, program musi dokona wyboru, jaka
jego sekcja ma by wykonywana. W takim przypadku moemy zastosowa instrukcj
warunkow if.
Instrukcja if moe mie 2 formy:
(if wyraenie
(instrukcja_1)
);if

lub
(if wyraenie
(instrukcja_1)
(instrukcja_2)
);if

;else

Wyraenie to tutaj co, co ma jak warto. Moe by to po prostu obiekt wybrany


przez nas do przechowywania zmiennej logicznej, ale moe to by te naprawd wyraenie, ktre najpierw trzeba obliczy, by w rezultacie tego pozna jego warto.
Najpierw zatem oblicza si warto wyraenia. Jeli nie jest ona rwna nil (prawda), to
wykonywana jest instrukcja_1. Jeli warto wyraenia jest rwna nil (fasz), to
instrukcja_1 nie jest wykonywana.
W drugiej wersji instrukcji if widzimy za napisem instrukcja_2 sowo komentarza else,
co mona przetumaczy jako: w przeciwnym razie. A zatem jeli w tej drugiej
sytuacji warto wyraenia jest rna od nil (prawda), to zostanie wykonana
instrukcja_1, w przeciwnym razie, czyli gdy warto wyraenia jest rwna nil (fasz),
zostanie wykonana instrukcja_2.
Oto prosty przykad:
;**************************************************PROG_012
;Przyklad instrukcji warunkowej IF.
;
;---------;przejscie na ekran tekstowy
(textscr)


233

BvupMJTQ!!qsbluzd{oz!lvst
;---------;pobranie wartosci zmiennej x
(setq
x (getint "\nPodaj liczbe calkowita: ") 
);setq
;---------;sprawdzenie warunku na x
(if (= x 10)

(princ "Zmienna x ma wartosc 10.")

(princ "Zmienna x ma wartosc inna niz 10.") ;else

);if
;---------(princ)
;---------;**************************************************KONIEC

Wykonanie powyszego programu moe by nastpujce:


Command: (load "prog_012")

Podaj liczbe calkowita: 2

Zmienna x ma wartosc inna niz 10.


Command:

Jeeli uytkownik wprowadzi liczb 10, ekran bdzie wyglda nastpujco:


Command: (load "prog_012")

Podaj liczbe calkowita: 10

Zmienna x ma wartosc 10.


Command:

Omwmy teraz wyrnione linie programu:


 Funkcja textscr przecza ekran AutoCADa na stron tekstow dziaanie
analogiczne jak klawisza funkcyjnego F1.
Funkcja ta moe by pomocna przy prowadzeniu duszego dialogu z uytkownikiem, poniewa standardowo ekran graficzny AutoCADa wywietla tylko
3 ostatnie linie tekstowe.
 W tym miejscu zmiennej x przypisujemy warto cakowit.
Funkcj odpowiedzialn za przypisanie do zmiennej x wartoci cakowitej jest
funkcja getint omwimy j sobie dokadnie w punkcie Pobieranie
informacji od uytkownika.
 To tutaj stosujemy instrukcj warunkow if, ktra sprawdza warto wyraenia
(= x 10)
  Poniewa w pierwszym powyszym przykadzie uytkownik wprowadzi z
klawiatury cyfr 2, wyraenie (= x 10) zwraca nil (fasz) i funkcja if wykonuje
instrukcj instrukcja_2 (warunek na else).
Gdyby uytkownik poda liczb 10, wwczas ewaluacja wyraenia (= x 10) daje
T (prawda) i wykonana zostaje instrukcja instrukcja_1.

9/!Qumf!j!lpotusvldkf!tufsvkdf

234

9/2/2/!Jotusvldkf!qsptuf!j!{p
9/2/2/!Jotusvldkf!qsptuf!j!{ppof
kf!qsptuf!j!{ppof
W jzyku AutoLISP rol symbolu kocowego instrukcji gra lewy skrajny nawias zamykajcy. Tak wic zapisy:
(setq x 3)

oraz
(setq
x 3
);setq

oraz
(setq
x
3
);setq

oraz
(
setq
x
3
)

w jzyku AutoLISP maj to samo znaczenie.


Dziki temu mona w tym jzyku pisa grupy instrukcji nie troszczc si o to, czy
zmieszcz si w jednym wierszu. Nie zezwala na to np. wikszo realizacji jzyka
BASIC. Jake czsto zdarza si, e po napisaniu wiersza
100 IF A > 5 OR B = 1 OR C < 0 (jaki dugi cig operacji,
ktry nie mieci si w jednym wierszu)

musisz napisa to od nowa jako podprogram, aby unikn kopotw!


Z drugiej strony, jeeli koniec wiersza nie ma adnego znaczenia, to skd interpreter
AutoLISPu bdzie wiedzia, ktre instrukcje naley wykona w razie spenienia warunku? Czsto bowiem zdarza si, e chodzi nam o wykonanie warunkowe nie jednej
instrukcji, a caego bloku instrukcji. Stosujemy wwczas instrukcj zoon zwan inaczej blokiem. S to po prostu zwyke instrukcje podane jako argumenty funkcji progn.
(progn
instrukcja_1
instrukcja_2
.....
instrukcja_n
);progn

Przyjto zasad, e wszdzie tam, gdzie mona napisa instrukcj prost, rwnie dobrze
wolno umieci instrukcj zoon.

235

BvupMJTQ!!qsbluzd{oz!lvst
Konstrukcja:
(if (warunek)
(progn
; instrukcja pusta
);progn
(progn ;else
lista_instrukcji
);progn
);if

jest rwnowana konstrukcji:


(if (not (warunek))
(progn
lista_instrukcji
);progn
);if

Oto przykad programu, w ktrym stosujemy instrukcje zoone:


;**************************************************PROG_013
;Przyklad instrukcji warunkowej IF
;z zastosowaniem instrukcji zlozonej.
;
;-------------------------------------------------;pobranie zmiennej x
(setq
x (getint "\nPodaj liczbe calkowita: ") 
);setq
;---------;sprawdzenie warunku na x
(if (= x 10)

(progn

(princ "Zmienna x ma wartosc 10.")
(princ "\nTrafiles.")
);progn
(progn ;else

(princ "Zmienna x ma wartosc inna niz 10.")
(princ "\nNie trafiles.")
);progn
);if
;---------(princ)
;---------;**************************************************KONIEC

Oto przykadowy wygld ekranu po wykonaniu tego programu:


Command: (load "prog_013")

Podaj liczbe calkowita: 10

Zmienna x ma wartosc 10.


Trafiles.
Command:

9/!Qumf!j!lpotusvldkf!tufsvkdf

236

Jeeli na zadane pytanie odpowiemy inaczej, to ekran moe wyglda tak:


Command: (load "prog_013")

Podaj liczbe calkowita: 5

Zmienna x ma wartosc inna niz 10.


Nie trafiles.
Command:

Omwmy teraz wyrnione linie programu:


 Pobieramy z klawiatury liczb cakowit (wykorzystujc funkcj getint), a
nastpnie liczb t podstawiamy pod zmienn x.
 Sprawdzamy warto wyraenia (= x 10). Wynik T (prawda) lub nil (fasz),
przekazujemy jako argument funkcji if.
 Wykorzystujc instrukcj grupujc progn, budujemy instrukcj zoon, ktra
ma zosta wykonana, gdy wyraenie (= x 10) jest prawdziwe zwraca T.
 Wykorzystujc instrukcj grupujc progn, budujemy instrukcj zoon else,
ktra ma zosta wykonana, gdy wyraenie (= x 10) jest faszywe zwraca nil.
Przypominam, e zrnicowane odstpy od lewego marginesu (wypenione biaymi
znakami), nie maj dla interpretera AutoLISPu adnego znaczenia. Pomagaj natomiast
programicie. Dziki nim program staje si bardziej czytelny.

9/2/3/![bhojfepof!jot
9/2/3/![bhojfepof!jotusvldkf!JG
bhojfepof!jotusvldkf!JG
Po warunku if lub else moe wystpi dowolny typ instrukcji. Moe to by instrukcja,
ktra wprowadza lub wyprowadza dane, wykonuje dziaania matematyczne lub wywouje funkcj uytkownika. Moe to by take kolejna instrukcja if. O instrukcji if, ktra
zawiera si wewntrz innej instrukcji if, mwimy, e jest zagniedona. Przykadowo,
w poniszym kodzie druga instrukcja if jest zagniedona w pierwszej:
(if (> x 1)
(if (< y 10)
(setq k1 1.25)
);if
);if

Drugi warunek if testuje si tylko wwczas, gdy prawdziwy jest warunek pierwszy, tak
wic zmiennej k1 jest przypisywana warto 1.25 tylko wtedy, kiedy obydwa warunki
s prawdziwe. To samo mona zapisa nastpujco:
(if (and (> x 1)(< y 10))
(setq k1 1.25)
);if

Obydwa zapisy powoduj wykonanie tego samego zadania, ale w drugim przykadzie,
dziki uyciu operatora logicznego and, zapis jest janiejszy. Nie trzeba rozszyfro-

237

BvupMJTQ!!qsbluzd{oz!lvst
wywa, co wykonuje kada instrukcja if; wystarczy odczyta instrukcj, by j zrozumie Jeli x jest wiksze ni 1 i y jest mniejsze ni 10, to k1 wynosi 1.25.
Generalnie, dwie nastpujce po sobie zagniedone instrukcje if mona zastpi jedn
z operatorem and. Z reguy mdrze jest ich unika, poniewa mog nas doprowadzi do
niejasnych sytuacji i trudnych do odczytania kodw.
Poniej przedstawiam przykad eksponujcy zastosowanie zagniedonej instrukcji
warunkowej if. Tym razem jest to temat szkolny i jednoczenie klasyczny w wielu
podrcznikach programowania, a mianowicie obliczenie pierwiastkw rwnania kwadratowego o postaci:
ax2 + bx + c = 0

Najpierw naley obliczy tzw. delt:


delta = b2 - 4ac

a potem, w zalenoci od wartoci delty, trzeba podj jedn z trzech akcji:


1. delta < 0

wypisanie komunikatu o braku pierwiastkw rzeczywistych

2. delta = 0
zastosowanie odpowiedniego wzoru w celu uzyskania wartoci
pierwiastka podwjnego, a nastpnie, po opatrzeniu odpowiednim komunikatem,
wyprowadzenie jej na ekran
3. delta > 0
zastosowanie odpowiednich wzorw do uzyskania wartoci dwch
rnych pierwiastkw rzeczywistych i podanie ich w odpowiedniej postaci
Program realizujcy powysze zadania moemy zrealizowa wykorzystujc zagniedone instrukcje warunkowe if else.
Oto program obliczajcy pierwiastki dwumianu kwadratowego:
;**************************************************PROG_014
;Obliczenie pierwiastkow rownania kwadratowego - wersja 1.
;
;-------------------------------------------------(textpage)

(princ "Obliczenie pierwiastkow rownania kwadratowego.")
(terpri)
(terpri)
;---------;pobranie wspolczynnikow a, b i c
;
(initget (+ 1 2))

(setq a (getreal "Podaj wartosc wspolczynnika a: "))
;
(initget 1)

(setq b (getreal "Podaj wartosc wspolczynnika b: "))
;
(initget 1)

(setq c (getreal "Podaj wartosc wspolczynnika c: "))
(terpri)

9/!Qumf!j!lpotusvldkf!tufsvkdf
;---------;obliczenie delty
;
(setq
delta (- (* b b)(* 4.0 a c))
);setq
;---------;obliczenie pierwiastkow rownania
;
(if (< delta 0)
(progn ;brak pierwiastkow rzeczywistych
(princ
(strcat
"\nDla wspolczynnikow "
(rtos a 2 4)
", "
(rtos b 2 4)
", "
(rtos c 2 4)
"\nwielomian kwadratowy nie ma "
"rozwiazan rzeczywistych."
);strcat
);princ
);progn

238





;delta = 0 i delta > 0
;
(if (= delta 0) ;podwojny pierwiastek rzeczywisty
(progn

(setq
x1 (/ (- b)(* 2.0 a))
);setq
(princ
(strcat
"\nDla wspolczynnikow "
(rtos a 2 4)
", "
(rtos b 2 4)
", "
(rtos c 2 4)
"\nwielomian kwadratowy ma "
"podwojny pierwiastek rzeczywisty"
"\nx1 = "
(rtos x1 2 4)
);strcat
);princ
);progn
(progn ;else - ostatnia, trzecia mozliwosc

;delta > 0 - 2 rozne pierwiastki rzeczywiste
;
(setq
x1 (/ (- (- b)(sqrt delta))(* 2.0 a))
x2 (/ (+ (- b)(sqrt delta))(* 2.0 a))
);setq

(progn

;else - w tym miejscu dopuszczamy 2 sytuacje:

239

BvupMJTQ!!qsbluzd{oz!lvst
(princ
(strcat
"\nDla wspolczynnikow "
(rtos a 2 4)
", "
(rtos b 2 4)
", "
(rtos c 2 4)
"\nwielomian kwadratowy ma "
"2 rozne pierwiastki rzeczywiste"
"\nx1 = "
(rtos x1 2 4)
"
"
"x2 = "
(rtos x2 2 4)
);strcat
);princ
);progn
);if
);progn
);if
;---------(terpri)
(princ)
;---------;**************************************************KONIEC

A oto moliwe przypadki wykonania programu:


Przypadek 1 brak pierwiastkw rzeczywistych
Command: (load "prog_014")

Obliczenie pierwiastkow rownania kwadratowego.


Podaj wartosc wspolczynnika a: 1

Podaj wartosc wspolczynnika b: 1

Podaj wartosc wspolczynnika c: 1

Dla wspolczynnikow 1.0000, 1.0000, 1.0000


wielomian kwadratowy nie ma rozwiazan rzeczywistych.
Command:

Przypadek 2 podwjny pierwiastek rzeczywisty


Command: (load "prog_014")

Obliczenie pierwiastkow rownania kwadratowego.


Podaj wartosc wspolczynnika a: 1

Podaj wartosc wspolczynnika b: -2

Podaj wartosc wspolczynnika c: 1

Dla wspolczynnikow 1.0000, -2.0000, 1.0000


wielomian kwadratowy ma podwojny pierwiastek rzeczywisty
x1 = 1.0000
Command:

9/!Qumf!j!lpotusvldkf!tufsvkdf

23:

Przypadek 3 dwa rne pierwiastki rzeczywiste


Command: (load "prog_014")

Obliczenie pierwiastkow rownania kwadratowego.


Podaj wartosc wspolczynnika a: 2

Podaj wartosc wspolczynnika b: -3

Podaj wartosc wspolczynnika c: 1

Dla wspolczynnikow 2.0000, -3.0000, 1.0000


wielomian kwadratowy ma 2 rozne pierwiastki rzeczywiste
x1 = 0.5000
x2 = 1.0000
Command:

Omwmy teraz wyrnione linie programu:


 Funkcja textpage powoduje wywietlenie ekranu tekstowego AutoCADa
z jednoczesnym wyczyszczeniem jego zawartoci.
 Funkcja initget ustala rne opcje, ktre mog by uyte przez nastpujc po
initget funkcj getxxx tutaj odnosi si to do wartoci wspczynnika
a. W konkretnym przypadku bity kontrolne oznaczaj:
1 nie pozwala na tzw. pusty ENTER
2 nie pozwala na wprowadzenie wartoci zerowej unikniemy w ten sposb
sprowadzenia rwnania kwadratowego do postaci liniowej
bx + c = 0

Dokadniej o funkcji initget powiemy sobie w punkcie Pobieranie informacji


od uytkownika.
 W liniach tych robimy zaoenia odnonie wartoci wspczynnikw b i c. Mog
by one dowolne, za wyjtkiem pustego ENTER.
 Instrukcja grupujca progn okrela nam instrukcje, ktre zostan wykonane
w przypadku, gdy delta bdzie mniejsza od zera rwnanie nie posiada
pierwiastkw rzeczywistych.
 Funkcja strcat zwraca acuch bdcy zoeniem (konkatenacj) wszystkich
swoich argumentw typu string. Otrzymany acuch podawany jest jako argument funkcji princ, ktra wywietla go na ekranie tekstowym.
Dokadniej o funkcji strcat powiemy sobie w punkcie Dziaania na acuchach.
 Jak ju wspomniaem wczeniej, argumenty funkcji stcat musz by acuchami
(typ string). Poniewa pierwiastki rwnania kwadratowego s zmiennymi typu
rzeczywistego, naley wpierw podda je konwersji na typ acuchowy. Kowersja
ta przeprowadzana jest za pomoc funkcji rtos. W naszym konkretnym przypadku funkcja rtos zwraca acuch obrazujcy format dziesitny zmiennej
z czterema cyframi po przecinku.
 Ten blok instrukcji ma zosta wykonany, gdy delta jest rwna lub wiksza od
zera.

241

BvupMJTQ!!qsbluzd{oz!lvst
 Tutaj dokonujemy kolejnego ucilenia warunku na delt. Ten blok instrukcji ma
zosta wykonany, gdy delta jest rwna zero.
W linii tej nastpuje zgrupowanie instrukcji w blok, ktry ma zosta wykonany,
gdy delta jest wiksza od zera.
Poniewa zastosowanie zagniedonych instrukcji warunkowych if prowadzi do otrzymania zawiego kodu, poniszy przykad pokazuje sposb obejcia tego problemu.
;**************************************************PROG_015
;Obliczenie pierwiastkow rownania kwadratowego - wersja 2.
;
;-------------------------------------------------(textpage)
(princ "Obliczenie pierwiastkow rownania kwadratowego.")
(terpri)
(terpri)
;---------;pobranie wspolczynnikow a, b i c
;
(initget (+ 1 2))
(setq a (getreal "Podaj wartosc wspolczynnika a: "))
;
(initget 1)
(setq b (getreal "Podaj wartosc wspolczynnika b: "))
;
(initget 1)
(setq c (getreal "Podaj wartosc wspolczynnika c: "))
(terpri)
;---------;obliczenie delty
;
(setq
delta (- (* b b)(* 4.0 a c))
);setq
;---------;obliczenie pierwiastkow rownania
;
(if (< delta 0)
(progn ;brak pierwiastkow rzeczywistych
(princ
(strcat
"\nDla wspolczynnikow "
(rtos a 2 4)
", "
(rtos b 2 4)
", "
(rtos c 2 4)
"\nwielomian kwadratowy nie ma "
"rozwiazan rzeczywistych."
);strcat
);princ
);progn
);if

9/!Qumf!j!lpotusvldkf!tufsvkdf
;
(if (= delta 0) ;podwojny pierwiastek rzeczywisty
(progn
(setq
x1 (/ (- b)(* 2.0 a))
);setq
(princ
(strcat
"\nDla wspolczynnikow "
(rtos a 2 4)
", "
(rtos b 2 4)
", "
(rtos c 2 4)
"\nwielomian kwadratowy ma "
"podwojny pierwiastek rzeczywisty"
"\nx1 = "
(rtos x1 2 4)
);strcat
);princ
);progn
);if
;
(if (> delta 0) ;2 rozne pierwiastki rzeczywiste
(progn
(setq
x1 (/ (- (- b)(sqrt delta))(* 2.0 a))
x2 (/ (+ (- b)(sqrt delta))(* 2.0 a))
);setq
(princ
(strcat
"\nDla wspolczynnikow "
(rtos a 2 4)
", "
(rtos b 2 4)
", "
(rtos c 2 4)
"\nwielomian kwadratowy ma "
"2 rozne pierwiastki rzeczywiste"
"\nx1 = "
(rtos x1 2 4)
"
"
"x2 = "
(rtos x2 2 4)
);strcat
);princ
);progn
);if
;---------(terpri)
(princ)
;---------;**************************************************KONIEC

242

243

BvupMJTQ!!qsbluzd{oz!lvst
Wykonanie powyszego programu jest dla uytkownika identyczne jak programu
PROG_014.LSP rnice widoczne s tylko z punktu widzenia programisty. Jak
wida w powyszym kodzie, wykorzystujc obliczon wczeniej delt, do obliczenia
pierwiastkw rwnania wykorzystano trzy proste instrukcje warunkowe if (bez
realizacji warunku typu else):
(if (< delta 0)
(progn
.....
);progn
);if
;
(if (= delta 0)
(progn
.....
);progn
);if
;
(if (> delta 0)
(progn
.....
);progn
);if

Sam program sta si przez to bardziej przejrzysty i zrozumiay.

Instrukcja while ma posta:


(while wyraenie
instrukcja_1
);while wyraenie

Najpierw oblicza si warto wyraenia. Jeli wynik jest rwny nil (fasz), wwczas
instrukcja_1 nie jest wcale wykonywana. Jeli jednak warto wyraenia jest rna od
nil (prawda), wwczas wykonywana jest instrukcja_1, po czym ponownie obliczana jest
warto wyraenia. Jeli nadal warto tego wyraenia jest rna od nil, wwczas
ponownie wykonywana jest instrukcja_1 i tak dalej, dopki (while!) wyraenie ma
warto rn od nil. Jeli w kocu kiedy obliczone wyraenie bdzie rwne nil,
wwczas dopiero ptla zostanie przerwana.
Obliczenie wartoci wyraenia odbywa si przed wykonaniem instrukcji
instrukcja_1.

Instrukcja_1 moe by instrukcj prost lub zoon.

9/!Qumf!j!lpotusvldkf!tufsvkdf

244

Naley zawsze pamita o umieszczeniu warunku wyjcia z ptli. Jeli jednak


zdarzy Ci si uruchomi nieskoczon ptl, moesz j bardzo prosto przerwa
naciskajc kombinacj klawiszy Ctrl-C. A tak na marginesie kombinacja
klawiszy Ctrl-C przerywa dowoln komend AutoCADa lub funkcj AutoLISPu.

Zastosowanie ptli while omwimy sobie na poniszych przykadach.

Qs{zlbe!2
W przykadzie tym, bdc w ptli while, pobieramy coraz to nowe wartoci zmiennej x.
Warunkiem opuszczenia ptli while jest nadanie zmiennej x wartoci zero.
;*************************************************PROG_016
;Wykorzystanie instrukcji WHILE - wersja 1.
;
;------------------------------------------------(textpage) ;przejscie na ekran tekstowy
;---------;nadanie zmiennej x wartosci nil
(setq x nil)
;---------;wejscie w petle while
(while (/= x 0)

(progn
;---------;pobranie nowej wartosci zmiennej x
(setq
x (getint

"Podaj nowa wartosc zmiennej x [0 - koniec]: "
);getint
);setq
;---------);progn
);while
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

A oto przykadowy wygld ekranu po wykonaniu programu:


Command: (load "prog_016")

Podaj nowa wartosc zmiennej x [0 - koniec]: 1

Podaj nowa wartosc zmiennej x [0 - koniec]: -10

Podaj nowa wartosc zmiennej x [0 - koniec]: 0

Command:

Omwmy teraz wyrnione linie programu:

245

BvupMJTQ!!qsbluzd{oz!lvst
 Wchodzimy w ptl while i rozpoczynamy pobieranie wartoci zmiennej
x. Wyraeniem, powodujcym dopuszczenie do wejcia w ptl jest (/= x 0).
Wyraenie to jest prawdziwe (zwraca T), gdy wczeniej zmiennej x zostaa
nadana warto nil.
 Pobieramy now warto zmiennej x, po czym wracamy na pocztek ptli while,
by ponownie porwna warunek (/= x 0). Jeli warunek jest prawdziwy,
pobieramy nastpn warto zmiennej x i znowu skaczemy na pocztek ptli.
Jeli warunek jest faszywy, omijamy ptl while i wykonujemy dalszy cig
instrukcji w tym przypadku jest to tylko instrukcja (princ), powodujca
niezauwaalne zakoczenie wykonywania programu.

Qs{zlbe!3
Program ten stanowi modyfikacj programu PROG_016. Ukazuje on inny sposb kontroli wyraenia, powodujcego wyjcie z ptli while.
;*************************************************PROG_017
;Wykorzystanie instrukcji WHILE - wersja 2.
;
;------------------------------------------------(textpage) ;przejscie na ekran tekstowy
;---------;nadanie zmiennej jeszcze wartosci T
(setq jeszcze T)

;---------;wejscie w petle while
(while jeszcze

(progn
;---------;pobranie nowej wartosci zmiennej x
(setq
x (getint

"Podaj nowa wartosc zmiennej x [0 - koniec]: "
);getint
);setq
;---------;zbadanie wartosci zmiennej x
(if (= x 0)

(progn
(setq jeszcze nil)

);progn
);if
;---------);progn
);while jeszcze
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

9/!Qumf!j!lpotusvldkf!tufsvkdf

246

Wykonanie programu jest identyczne jak dla programu PROG_016 rnice s widoczne jedynie dla programisty.
Omwmy teraz wyrnione linie programu:
 Inicjalizujemy zmienn jeszcze i nadajemy jej warto T (prawda). Zmienna ta
bdzie sterowa ptl while.
 Poniewa wczeniej zmiennej jeszcze nadano warto T, wchodzimy w ptl
while.
 Pobieramy now warto zmiennej x.
 Sprawdzamy, czy zmienna x jest rwna zero.
 Jeeli zmienna x jest rwna zero, ustawiamy warto zmiennej jeszcze na nil,
umoliwiajc tym samym opuszczenie ptli while.

Qs{zlbe!4
W przykadzie tym, wykorzystujemy instrukcj while do obliczenia i wypisania na
ekranie tekstowym kwadratw liczb cakowitych od 1 do 10.
;*************************************************PROG_018
;Wykorzystanie instrukcji WHILE.
;
;Program do obliczania kwadratow liczb calkowitych
;od 1 do 10.
;------------------------------------------------(textpage) ;przejscie na ekran tekstowy
;---------(setq liczba 1)

(princ "\nKwadraty liczb calkowitych od 1 do 10.\n")
(princ "\nLiczba
Kwadrat liczby\n")
(while (< liczba 11)

(progn
(setq kwadrat (* liczba liczba))

(princ

(strcat
" "
(rtos liczba 2 0)
"
"
(rtos kwadrat 2 0)
);strcat
);princ
(terpri)

(setq liczba (1+ liczba))

);progn
);while
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

247

BvupMJTQ!!qsbluzd{oz!lvst
Po wykonaniu programu ekran tekstowy bdzie wyglda nastpujco:
Command: (load "prog_018")

Kwadraty liczb calkowitych od 1 do 10.


Liczba
1
2
3
4
5
6
7
8
9
10
Command:

Kwadrat liczby
1
4
9
16
25
36
49
64
81
100

Omwmy teraz wyrnione linie programu:


 Ustawiamy warto zmiennej liczba na 1.
 Tutaj rozpoczyna si ptla, ktra zostanie wykonana, poniewa warto
zmiennej liczba jest mniejsza ni 11. Gdyby liczba ju na pocztku bya rwna
11, wwczas ptla nie wykonaaby si ani razu.
 Obliczany kwadrat danej liczby. Wynik podstawiany jest pod zmienn kwadrat.
 Uywajc funkcji princ, strcat oraz rtos, wypisujemy w jednym wierszu dan
liczb oraz jej kwadrat.
 To tutaj nastpuje przejcie do nowej linii.
 Zwikszamy warto zmiennej liczba o 1. Gdybymy o tym zapomnieli,
wwczas jedynym sposobem na opuszczenie ptli while byoby przerwanie
wykonywania programu poprzez nacinicie kombinacji klawiszy Ctrl-C.

9/3/2/![bhojfepof!jotusv
9/3/2/![bhojfepof!jotusvldkf!XIJ
fepof!jotusvldkf!XIJMF
ldkf!XIJMF
Aby zapewni sobie dwa poziomy powtarzania, moemy zagniedzi ptle while.
Mona na przykad zastosowa zewntrzn ptl w celu powtarzania caego programu,
dopki uytkownik nie zadecyduje inaczej, oraz wewntrzn do sprawdzania
poprawnoci danych wejciowych.
Poniszy program pokazuje wykorzystanie zagniedonych ptli while do wypisania na
ekranie tekstowym liczb od 1 do 100 w 10 rzdach po 10 kolumn.
;*************************************************PROG_019
;Wykorzystanie zagniezdzonych instrukcji WHILE.
;
;Wypisanie liczb od 1 do 100 w 10 rzedach po 10 kolumn.
;
;-------------------------------------------------

9/!Qumf!j!lpotusvldkf!tufsvkdf
(textpage)
;---------(princ "\nWykorzystanie zagniezdzonych instrukcji WHILE.")
(princ
(strcat
"\nWypisanie liczb od 1 do 100 "
"w 10 rzedach po 10 kolumn."
);strcat
);princ
(princ "\n\n")
;---------(setq rzad 1)

;
(while (< rzad 11)

(progn
;---------(setq

kolumna 1
liczba 1
);setq
;---------(while (< kolumna 11)

(progn
;---------(princ (+ liczba (* 10 (- rzad 1))))

(princ " ")

;---------(setq

kolumna (1+ kolumna)
liczba (1+ liczba)
);setq
;---------);progn
);while kolumna
;---------(princ "\n")

(setq rzad (1+ rzad))

;---------);progn
);while rzad
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

Wykonanie programu bdzie nastpujce:


Command: (load "prog_019")

Wykorzystanie zagniezdzonych instrukcji WHILE.


Wypisanie liczb od 1 do 100 w 10 rzedach po 10 kolumn.
1 2 3 4
11 12 13
21 22 23

5 6 7 8
14 15 16
24 25 26

9 10
17 18
27 28

19
29

20
30

248

249

BvupMJTQ!!qsbluzd{oz!lvst
31 32 33
41 42 43
51 52 53
61 62 63
71 72 73
81 82 83
91 92 93
Command:

34
44
54
64
74
84
94

35
45
55
65
75
85
95

36
46
56
66
76
86
96

37
47
57
67
77
87
97

38
48
58
68
78
88
98

39
49
59
69
79
89
99

40
50
60
70
80
90
100

Omwmy teraz wyrnione linie programu.


 Ustawiamy warto pocztkow zmiennej rzad.
 Wchodzimy w zewntrzn ptl while. Ptl t wykonujemy tak dugo, dopki
zmienna rzad jest mniejsza od 11.
 Ustawiamy wartoci pocztkowe zmiennych kolumna i liczba dla kolejnego
rzdu liczb.
 Wchodzimy w wewntrzn ptl while. Ptl t wykonujemy tak dugo, dopki
zmienna kolumna jest mniejsza od 11.
 Obliczamy aktualn warto liczby, po czym wypisujemy j uywajc instrukcji
princ.
 Oddzielamy od siebie dwoma spacjami poszczeglne liczby w rzdzie.
 Zwikszamy o 1 wartoci zmiennych kolumna i liczba, zapewniajc tym samym
dalszy prawidowy przebieg ptli wewntrznej.
 Bdc ju poza ptl wewntrzn przechodzimy do nowego wiersza, umoliwiajc tym samym prawidowe wypisanie kolejnego rzdu liczb.
Zwikszamy o 1 warto zmiennej rzad, zapewniajc tym samym dalszy prawidowy przebieg ptli zewntrznej.

W pewnych okolicznociach trzeba w zalenoci od wyniku jakiego testu, wybra


jedn z wielu drg. Konstrukcja if ... else daje do wyboru tylko dwie moliwoci
dalszego postpowania, chocia pozwala te stosowa rodzaj zagniedania jednych
konstrukcji w innych, na przykad:
if (warunek_1)
czynnosc_1
else
if (warunek_2)
czynnosc_2
else

9/!Qumf!j!lpotusvldkf!tufsvkdf

24:

if (warunek_3)
czynnosc_3
itd.

Jest to jednak zdecydowanie nieznony sposb rozwizania tego problemu. W jzyku


AutoLISP istnieje mechanizm, zwany instrukcj cond (zwrotnica), ktry pozwala
wybra jeden spord wielu skokw.
Format instrukcji cond jest nastpujcy:
(cond (test_1 result_1) ..... (test_n result_n))

Argumentami funkcji moe by dowolna liczba list. Funkcja testuje wyraenia test,
wyznaczajc warto pierwszych elementw kadej kolejnej listy podrzdnej (w podanym porzdku), a do momentu, gdy warto ktrego z nich okae si rna od nil.
Nastpnie wartociowane jest to wyraenie result, ktre wystpuje po pozytywnie
przetestowanym wyraeniu test i zwracana jest warto ostatniego wyraenia listy
podrzdnej.
Zwykle jako ostatnie wyraenie test uywa si T (jest ono uwzgldniane w przypadku
braku pozytywnego wyniku testowania wszystkich poprzednich).
Typowym przykadem zastosowania tej instrukcji moe by program zarzdzania
danymi, ktrego dziaaniem steruje si za porednictwem menu. Uytkownik programu
otrzymuje nastpujce menu:
Mozliwe opcje programu:
1.
2.
3.
4.
5.
6.

Utworz nowy plik.


Dolacz jeden element do pliku.
Usun jeden element z pliku.
Wypisz jeden element z pliku.
Przeszukaj plik.
Zakoncz prace.

Wybierz opcje [1-6]:

Jest sze funkcji przeznaczonych do wykonywania tych zada oraz funkcja o nazwie
MENU, zarzdzajca pozostaymi funkcjami.
A oto i program realizujcy powysze zadania:
;*************************************************PROG_020
;Przyklad uzycia instrukcji COND - wersja 1.
;
;=================================================
;definicje poszczegolnych funkcji programu
;
;------------------------------------------------;
(defun NOWY_PLIK ()

(progn
;---------(princ "\nWybrales opcje NOWY PLIK.")

251

BvupMJTQ!!qsbluzd{oz!lvst
;---------;cialo_funkcji
;---------(princ)
;---------);progn
);NOWY_PLIK
;
;------------------------------------------------;
(defun DOPISZ_ELEMENT ()
(progn
;---------(princ "\nWybrales opcje DOPISZ ELEMENT.")
;---------;cialo_funkcji
;---------(princ)
;---------);progn
);DOPISZ_ELEMENT
;
;------------------------------------------------;
(defun USUN_ELEMENT ()
(progn
;---------(princ "\nWybrales opcje USUN ELEMENT.")
;---------;cialo_funkcji
;---------(princ)
;---------);progn
);USUN_ELEMENT
;
;------------------------------------------------;
(defun WYPISZ_ELEMENT ()
(progn
;---------(princ "\nWybrales opcje WYPISZ ELEMENT.")
;---------;cialo_funkcji
;---------(princ)
;---------);progn
);WYPISZ_ELEMENT
;
;------------------------------------------------;
(defun SZUKAJ ()
(progn
;----------

9/!Qumf!j!lpotusvldkf!tufsvkdf
(princ "\nWybrales opcje SZUKAJ.")
;---------;cialo_funkcji
;---------(princ)
;---------);progn
);SZUKAJ
;
;------------------------------------------------;
(defun ZAKONCZ_PRACE ()
(progn
;---------(princ "\nWybrales opcje ZAKONCZ PRACE.")
;---------;cialo_funkcji
;---------(setq jeszcze nil)
;---------(princ)
;---------);progn
);ZAKONCZ PRACE
;
;------------------------------------------------;Funkcja glowna
;
(defun MENU ()
(progn
;---------(setq jeszcze T)
(while jeszcze
(progn
;---------(textpage)
;---------;wypisanie zawartosci menu
(princ
(strcat
"\nMozliwe opcje programu:"
"\n1. Utworz nowy plik."
"\n2. Dolacz jeden element do pliku."
"\n3. Usun jeden element z pliku."
"\n4. Wypisz jeden element z pliku."
"\n5. Przeszukaj plik."
"\n6. Zakoncz prace."
);strcat
);princ
(terpri)
;---------;pobranie numeru opcji
(setq
opcja (getint

252





253

BvupMJTQ!!qsbluzd{oz!lvst
"\nWybierz opcje [1-6]: "
);getint
);setq
;---------(textpage)
;---------;wywolanie funkcji zwiazanej z numerem podanej opcji
(cond

((= opcja 1)(NOWY_PLIK))
((= opcja 2)(DOPISZ_ELEMENT))
((= opcja 3)(USUN_ELEMENT))
((= opcja 4)(WYPISZ_ELEMENT))
((= opcja 5)(SZUKAJ))
((= opcja 6)(ZAKONCZ_PRACE))
(T (princ "\nNiepoprawny przypadek."))

);cond
;---------;zatrzymanie realizacji programu do chwili nacisniecia

;klawisza ENTER
(getstring "\n\nNacisnij ENTER...")
;---------);progn
);while jeszcze
;---------(princ)
;---------);progn
);MENU
;
;------------------------------------------------;
;koniec definicji funkcji
;=================================================
;wywolanie funkcji MENU
(MENU)

;=================================================
(princ)
;*************************************************KONIEC

Wykonanie powyszego programu moe by nastpujce:


Command: (load "prog_020")

Mozliwe opcje programu:


1. Utworz nowy plik.
2. Dolacz jeden element do pliku.
3. Usun jeden element z pliku.
4. Wypisz jeden element z pliku.
5. Przeszukaj plik.
6. Zakoncz prace.
Wybierz opcje [1-6]: 3

Wybrales opcje USUN ELEMENT

9/!Qumf!j!lpotusvldkf!tufsvkdf

254

Nacisnij ENTER...

Mozliwe opcje programu:


1. Utworz nowy plik.
2. Dolacz jeden element do pliku.
3. Usun jeden element z pliku.
4. Wypisz jeden element z pliku.
5. Przeszukaj plik.
6. Zakoncz prace.
Wybierz opcje [1-6]: 7

Niepoprawny przypadek.
Nacisnij ENTER...

Mozliwe opcje programu:


1. Utworz nowy plik.
2. Dolacz jeden element do pliku.
3. Usun jeden element z pliku.
4. Wypisz jeden element z pliku.
5. Przeszukaj plik.
6. Zakoncz prace.
Wybierz opcje [1-6]: 6

Wybrales opcje ZAKONCZ PRACE


Nacisnij ENTER...

Command:

Omwmy teraz wyrnione linie programu:


 Uywajc funkcji defun, definiujemy poszczeglne funkcje naszego programu.
Funkcje te s to tylko funkcje prototypowe nie robi nic poza wypisaniem
nazwy wybranej komendy (za wyjtkiem funkcji ZAKONCZ_PRACE).
 W linii tej, bdcej instrukcj funkcji ZAKONCZ_PRACE, poprzez nadanie
zmiennej jeszcze wartoci nil, opuszczamy ptl while.
 Definiujemy nasz funkcj gwn MENU.
 Nadajemy zmiennej jeszcze warto T (prawda), umoliwiajc tym samym
wejcie w ptl while.
 Wchodzimy w ptl while.
 Uywajc funkcji princ oraz strcat, wypisujemy menu uytkownika.
 W linii tej, liczba cakowita, bdca odpowiedzi (wyborem) uytkownika,
zostaje podstawiona pod zmienn opcja.
 To tutaj wykorzystujemy instrukcj cond, aby dokona wyboru wielowariantowego. Jeli zmienna opcja = 1, to bdzie wywoana funkcja NOWY_PLIK, jeli
za zmienna opcja = 2, to zostanie wywoana funkcja DOPISZ_ELEMENT itd.

255

BvupMJTQ!!qsbluzd{oz!lvst
W linii tej, widzimy, jak w instrukcji cond zastosowa opcj domyln. Jeeli
warto zmiennej opcja bdzie mniejsza ni 1 lub wiksza ni 6, to instrukcja
cond wybierze instrukcje wystpujce po staej predefiniowanej T wypisze
komunikat "Niepoprawny przypadek.", po czym zostanie ponowiony wybr
opcji z menu.

Wywoujemy wczeniej zdefiniowan funkcj MENU. Postpowanie takie automatycznie wywouje funkcj MENU zaraz po pomylnym zaadowaniu
programu do interpretera AutoLISPu.
Naley zwrci szczegln uwag na odpowiedni liczb nawiasw, oddzielajcych od siebie poszczeglne warunki.

Na przykad zapis:
(cond
((= x1 1)
;lista_instrukcji
)
((and (= x1 2)(/= x3 0))
;lista_instrukcji
)
);cond

jest poprawny, podczas gdy zapis:


(cond
(= x1 1)
;lista_instrukcji
)
(and (= x1 2)(/= x3 0))
;lista_instrukcji
)
);cond

jest zapisem bdnym. W takim przypadku interpreter powinien zasygnalizowa bd


zamknicia nawiasw. Jeeli jednak pomylisz si rwnie w liczbie nawiasw w lista_
instrukcji tak, e ich liczba bdzie zgodna, mog powsta bdy trudne do zlokalizowania.
Aby unikn takiego przypadku, moesz stosowa nastpujc konstrukcj:
(cond
(;przypadek 1
(= x1 1)
(progn
;lista_instrukcji_1
);progn
);koniec przypadku 1
;
(;rzypadek 2
(and (= x1 2)(/= x3 0))
(progn
;lista_instrukcji_2
);progn

9/!Qumf!j!lpotusvldkf!tufsvkdf

256

);koniec przypadku 2
;
.....
;
(;przypadek n
(warunek_n)
(progn
;lista_instrukcji_n
);progn
);koniec przypadku n
);cond

Zapis taki jest przejrzysty i czytelny, mona rwnie atwo zlokalizowa odpowiadajc
sobie par nawiasw.
Wrmy jednak do naszego programu. Funkcja gwna MENU wywoywana bya z ptli while. Po wyborze i wykonaniu funkcji z menu 1 5, nastpowao ponowne
wywoanie funkcji MENU. Co jednak zrobi, jeli chcemy, aby funkcja MENU bya
wywoywana jednokrotnie (tzn. wykonywaa jedn z funkcji podrzdnych, po czym
opuszczaa ptl while)?
Odpowied jest bardzo prosta. Wystarczy do kadej funkcji pomocniczej dopisa na
kocu instrukcj ustalajc warto zmiennej jeszcze na nil.
Program PROG_021, znajdujcy si na doczonej dyskietce, zawiera odpowiednie
zmiany, pozwalajce na dziaanie w wyej wymieniony sposb.
Ostatnim przykadem uycia instrukcji cond bdzie program obliczajcy pierwiastki
rwnania kwadratowego.
;**************************************************PROG_022
;Wykorzystanie instrukcji COND.
;Obliczenie pierwiastkow rownania kwadratowego.
;
;-------------------------------------------------(textpage)
(princ "Obliczenie pierwiastkow rownania kwadratowego.")
(terpri)
(terpri)
;---------;pobranie wspolczynnikow a, b i c
;
(initget (+ 1 2))
(setq a (getreal "Podaj wartosc wspolczynnika a: "))
;
(initget 1)
(setq b (getreal "Podaj wartosc wspolczynnika b: "))
;
(initget 1)
(setq c (getreal "Podaj wartosc wspolczynnika c: "))
(terpri)
;---------;obliczenie delty

257

BvupMJTQ!!qsbluzd{oz!lvst
;
(setq
delta (- (* b b)(* 4.0 a c))
);setq
;---------;obliczenie pierwiastkow rownania
;
(cond
((< delta 0)
(progn ;brak pierwiastkow rzeczywistych
(princ
(strcat
"\nDla wspolczynnikow "
(rtos a 2 4)
", "
(rtos b 2 4)
", "
(rtos c 2 4)
"\nwielomian kwadratowy nie ma "
"rozwiazan rzeczywistych."
);strcat
);princ
);progn
);koniec delta < 0
;
((= delta 0) ;podwojny pierwiastek rzeczywisty
(progn
(setq
x1 (/ (- b)(* 2.0 a))
);setq
(princ
(strcat
"\nDla wspolczynnikow "
(rtos a 2 4)
", "
(rtos b 2 4)
", "
(rtos c 2 4)
"\nwielomian kwadratowy ma "
"podwojny pierwiastek rzeczywisty"
"\nx1 = "
(rtos x1 2 4)
);strcat
);princ
);progn
);koniec delta = 0
;
((> delta 0) ;2 rozne pierwiastki rzeczywiste
(progn
(setq
x1 (/ (- (- b)(sqrt delta))(* 2.0 a))
x2 (/ (+ (- b)(sqrt delta))(* 2.0 a))
);setq
(princ




9/!Qumf!j!lpotusvldkf!tufsvkdf

258

(strcat
"\nDla wspolczynnikow "
(rtos a 2 4)
", "
(rtos b 2 4)
", "
(rtos c 2 4)
"\nwielomian kwadratowy ma "
"2 rozne pierwiastki rzeczywiste"
"\nx1 = "
(rtos x1 2 4)
"
"
"x2 = "
(rtos x2 2 4)
);strcat
);princ
);progn
);koniec delta > 0
);cond
;---------(terpri)
(princ)
;---------;**************************************************KONIEC

Wykonanie powyszego programu jest identyczne, jak w programach PROG_014


i PROG_015, gdzie uywalimy instrukcji warunkowej if.
Omwmy teraz wyrnione linie programu:
 Wchodzimy w instrukcj cond i rozpoczynamy sprawdzanie wartoci zmiennej
delta.
 Ten fragment programu wykonywany jest wwczas, gdy zmienna delta jest
mniejsza od zera.
 Ten fragment programu wykonywany jest wwczas, gdy zmienna delta jest
rwna zero.
 Ten fragment programu wykonywany jest wwczas, gdy zmienna delta jest
wiksza od zera.

Ptla repeat posiada nastpujcy format:


(repeat number expr_1 ..... expr_n)

W funkcji tej argument number jest dowoln dodatni liczb typu integer. Funkcja
dokonuje wartociowania kadego argumentu expr tyle razy, ile okrela argument
number i zwraca warto ostatniego z nich.

259

BvupMJTQ!!qsbluzd{oz!lvst
Funkcja ta jest podobna do by moe znanej Ci z innych jzykw programowania
funkcji for. Jej dziaanie przeledzimy na poniszym przykadzie. Bdzie to modyfikacja programu PROG_018, ktry oblicza i wypisuje kwadraty liczb cakowitych od 1 do
10. W programie PROG_018, zostaa do tego celu uyta funkcja while. W poniszym
programie poka Ci, jak rozwiza to zadanie przy pomocy ptli repeat.
A oto i nasz program:
;*************************************************PROG_023
;Wykorzystanie instrukcji REPEAT.
;
;Program do obliczania kwadratow liczb calkowitych
;od 1 do 10.
;------------------------------------------------(textpage) ;przejscie na ekran tekstowy
;---------(setq liczba 1)
(princ "\nKwadraty liczb calkowitych od 1 do 10.\n")
(princ "\nLiczba
Kwadrat liczby\n")
(repeat 10 ;zmiana w stosunku do PROG11

(progn
(setq kwadrat (* liczba liczba))
(princ
(strcat
" "
(rtos liczba 2 0)
"
"
(rtos kwadrat 2 0)
);strcat
);princ
(terpri)
(setq liczba (1+ liczba))
);progn
);repeat
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

Po wykonaniu programu ekran bdzie wyglda identycznie, jak w programie


PROG_018.
Omwmy teraz wyrnione linie programu:
 Instrukcja (while (< liczba 11) ...) zostaa zastpiona instrukcj (repeat 10 ...).
Jest to jedyna zmiana dokonana w stosunku do programu PROG_018.
Zastosowanie instrukcji while czy instrukcji repeat zaley od tego, co chcemy
uzyska. Instrukcj repeat stosujemy wwczas, gdy znamy liczb powtrze
ptli. Instrukcj while moemy stosowa zarwno wtedy, gdy znamy liczb
powtrze ptli, jak rwnie wtedy, gdy liczba powtrze nie jest znana, a zakoczenie ptli zalene jest od spenienia danego warunku.

9/!Qumf!j!lpotusvldkf!tufsvkdf

25:

9/5/2/![bhojfepof!jotu
9/5/2/![bhojfepof!jotusvldkf!SF
hojfepof!jotusvldkf!SFQFBU
svldkf!SFQFBU
Zagniedanie instrukcji repeat jest identyczne jak instrukcji while, co zobrazowano na
poniszym przykadzie.
;*************************************************PROG_024
;Wykorzystanie zagniezdzonych instrukcji REPEAT.
;
;Wypisanie liczb od 1 do 100 w 10 rzedach po 10 kolumn.
;
;------------------------------------------------(textpage)
;---------(princ "\nWykorzystanie zagniezdzonych instrukcji REPEAT.")
(princ
(strcat
"\nWypisanie liczb od 1 do 100 "
"w 10 rzedach po 10 kolumn."
);strcat
);princ
(princ "\n\n")
;---------(setq rzad 1)
;
(repeat 10

(progn
;---------(setq
kolumna 1
liczba 1
);setq
;---------(repeat 10

(progn
;---------(princ (+ liczba (* 10 (- rzad 1))))
(princ " ")
;---------(setq
kolumna (1+ kolumna)
liczba (1+ liczba)
);setq
;---------);progn
);repeat
;---------(princ "\n")
(setq rzad (1+ rzad))
;---------);progn
);repeat
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

261

BvupMJTQ!!qsbluzd{oz!lvst
Po wykonaniu programu ekran bdzie wyglda identycznie, jak w programie
PROG_019.
Omwmy teraz wyrnione linie programu, ktre obrazuj zmiany w stosunku do kodu
z programu PROG_019:
 Instrukcja (while (< rzad 11) .....), bdca ptl zewntrzn, zostaa zastpiona
instrukcj (repeat 10 .....) liczba powtrze ptli wynosi 10.
 Instrukcja (while (< kolumna 11) .....), bdca ptl wewntrzn, zostaa
zastpiona instrukcj (repeat 10 .....) liczba powtrze ptli wynosi 10.

Jeli programowae ju w jakim innym jzyku, jedn z pierwszych poznanych


instrukcji bya zapewne ptla for. Ma ona nastpujc form (przykad z jzyka C):
for (instr_ini ; wyraz_warun ; instr_krok)
tresc_petli

co w przykadzie moe wyglda choby tak:


for (i=0 ; i<10 ; i=i+1)
{
printf ("\nJestem w petli for.");
}

Wyjanijmy sobie teraz, co oznaczaj poszczeglne czony:


for (ang. dla...) oznacza: dla takich warunkw rb...
instr_ini jest to instrukcja wykonywana zanim ptla zostanie po raz pierwszy
uruchomiona. W naszym przykadzie jest to podstawienie i=0.
wyraz_warun jest to wyraenie, ktre obliczane jest przed kadym obiegiem
ptli. Jeli jest ono rne od zera, to wykonywane zostaj instrukcje bdce
treci ptli. U nas wyraeniem warunkowym jest wyraenie i<10. Jeli rzeczywicie i jest mniejsze od 10, wwczas wykonana zostaje instrukcja bdca
treci ptli, czyli wypisanie tekstu "\nJestem w ptli for."
instr_krok to instrukcja wykonywana na zakoczenie kadego obiegu ptli.
Jest to jakby ostatnia instrukcja, wykonywana bezporednio przed obliczeniem
wyraenia wyraz_warun. U nas jest to po prostu i=i+1.
Praca tej ptli odbywa si wic jakby wedug takiego harmonogramu:
1. Najpierw wykonuj si instrukcje inicjalizujce prac ptli.

9/!Qumf!j!lpotusvldkf!tufsvkdf

262

2. Obliczane jest wyraenie warunkowe. Jeli jest rwne 0 praca ptli jest
przerywana.
3. Jeli powyej okazao si, e wyraenie byo rne od zera, wwczas wykonywane zostaj instrukcje bdce treci ptli.
4. Po wykonaniu treci ptli wykonana zostaje instrukcja inst_krok, po czym powtarzana jest akcja 2).
Pora teraz na wyjanienie, dlaczego w celu omwienia ptli for posuyem si przykadem
z jzyka C. Ot w standardowych funkcjach jzyka AutoLISP nie ma definicji ptli for!!!
Jest wprawdzie instrukcja repeat, lecz nie jest to jeszcze ptla for w caej okazaoci.
Powyszy problem da si jednak obej. Jzyk AutoLISP oferuje nam konstrukcj tzw.
listy-funkcji. Poniewa funkcja jest list, wic po prostu zbudujmy j jak list, a nastpnie wykonajmy jako funkcj. Pisanie programw wykorzystujcych takie sztuczki jest
moliwe tylko w LISPie. Inne jzyki nie pozwalaj na traktowanie obiektu raz jako
danej (lista), a raz jako czci programu (funkcja).
Temat listy-funkcji zostanie omwiony dokadnie podczas omawiania funkcji, teraz
wic zostanie zaprezentowana definicja ptli FOR, ktrej autorami s Panowie: Maciej
Horczyczak i Jacek Skierski ksika AutoLISP dla uytkownikw AutoCADa.
;*************************************************PROG_025
;Maciej Horczyczak & Jacek Skierski
;
;Petla FOR (jak w BASIC'u)
;(for 'zm_ster
;
war_pocz_zm_ster
war_kon_zm_ster
krok_zm_ster
;
'lista instrukcji)
;
;Przyklady wywolania:
;
;(for 'i 10 0 -3 '(print i))
;
;(for 'i 1 10 1
; '(progn
;
(print i)
;
(print (+ i 1))
;
);progn
;);for i
;
;------------------------------------------------(defun FOR ( zmster ip ik ki zakres / fun w )
(progn
(if (> ki 0)
(setq w (eval '<=))
(setq w (eval '>=))
);if
(setq fun (list (list '/ ) zakres))
(set zmster ip)
(while (w (eval zmster) ik)
(FUN)

263

BvupMJTQ!!qsbluzd{oz!lvst
(set zmster (+ ki (eval zmster)))
);while
(setq fun nil)
(princ)
);progn
);FOR
;
;*************************************************KONIEC

O definicji ptli FOR powiemy sobie podczas omawiania definiowania wasnych


funkcji, teraz tylko podam kilka przykadw jej wykorzystania.

Qs{zlbe!2
W przykadzie tym, po pobraniu wartoci pocztkowej, kocowej oraz kroku ptli,
wypisujemy na ekran wybrane liczby.
;*************************************************PROG_026
;Wykorzystanie petli FOR - przyklad 1.
;
;------------------------------------------------;odszukanie i zaladowanie pliku PROG_025.LSP
;
(setq plik (findfile "prog_025.lsp"))

(if plik
(progn ;plik zostal znaleziony
(load plik)

);progn
(progn ;else - nia znaleziono pliku
(alert

(strcat
"Nie znaleziono pliku PROG_025.LSP!!!"
"\nWykonywanie programu przerwane."
);strcat
);alert
(exit)

);progn
);if
;---------;jesli plik prog_025 zostal znaleziony
;wykorzystanie petli for
;
(textpage) ;przejscie na ekran tekstowy
;
(princ "\nPrzyklad wykorzystania petli for.")
;
(initget (+ 1 2 4))

(setq x1 (getint "\nPodaj wartosc poczatkowa petli: "))
;
(initget (+ 1 2 4))
(setq x2 (getint "\nPodaj wartosc koncowa petli: "))
;

9/!Qumf!j!lpotusvldkf!tufsvkdf

264

(initget (+ 1 2 4))
(setq x3 (getint "\nPodaj krok petli: "))
;
(princ
(strcat
"\nWypisywanie od "
(rtos x1 2 0)
" do "
(rtos x2 2 0)
" z krokiem = "
(rtos x3 2 0)
".\n"
);strcat
);princ
;
(for 'i x1 x2 x3

'(progn

(princ i)

(terpri) ;przejscie do nowej linii
);progn
);for i
;
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

Wykonanie programu moe by nastpujce:


Command: (load "prog_026")

Przyklad wykorzystania petli for.


Podaj wartosc poczatkowa petli: 1

Podaj wartosc koncowa petli: 10

Podaj krok petli: 2

Wypisywanie od 1 do 10 z krokiem = 2.
1
3
5
7
9
Command:

Omwmy teraz wyrnione linie programu:


 Wykorzystujc standardow funkcj AutoLISPu findfile, poszukujemy pliku
z definicj ptli FOR.
Format funkcji findfile jest nastpujcy:
(findfile filename)

265

BvupMJTQ!!qsbluzd{oz!lvst
Funkcja ta poszukuje okrelonego pliku (w naszym przypadku jest to plik
PROG_025.LSP) w bibliotecznej ciece poszukiwa AutoCADa. Jeli podany
plik zostanie znaleziony, funkcja zwraca pen nazw pliku wraz ze ciek
dostpu, w przeciwnym wypadku funkcja zwraca nil.
Warto zwracana przez funkcj findfile jest nastpnie podstawiana pod zmienn plik.
 Jeli plik PROG_025.LSP zosta znaleziony, funkcja load powoduje jego
zaadowanie.
 Jeli plik PROG_025.LSP nie zosta znaleziony, standardowa funkcja AutoLISPu
alert powoduje wypisanie w oknie dialogowym podanego acucha tekstu.
 Funkcja exit wymusza zakoczenie biecego programu uytkowego. Wywoujemy j po wywietleniu komunikatu ostrzegawczego w oknie dialogowym.
Gdyby funkcja ta nie zostaa tutaj zastosowana, w trakcie realizacji dalszej
czci programu otrzymalibymy komunikat o bdzie gdy wystpiaby
prba wywoania niezdefiniowanej funkcji FOR.
 Zapis (initget (+ 1 2 4)) jest rwnowany zapisowi (initget 5). Nie dopuszcza on
do podania pustego ENTER, liczby zerowej lub liczby ujemnej podczas najbliszego wywoania funkcji entsel, nentsel lub getxxx (za wyjtkiem getstring,
getenv i getvar).
 To tutaj wywoujemy nasz ptl FOR. Oprcz podania wartoci pocztkowej,
kocowej oraz kroku ptli, pierwszym argumentem funkcji jest nazwa zmiennej
sterujcej prac ptli.
Nazwa zmiennej sterujcej prac ptli musi by poprzedzona apostrofem (tzn. musi
by kwotowana). Jeli o tym zapomnisz, program moe da nieoczekiwane rezultaty.

 Instrukcja progn grupuje nam instrukcje, ktre naley wykona w ptli.


Instrukcja grupujca progn musi by take kwotowana.

 Wypisujemy na ekranie tekstowym liczby speniajce podane wymagania.

Qs{zlbe!3
Analizujc wygld ekranu w przykadzie pierwszym, z pewnoci zauwaye dodatkowe odstpy pomidzy wartoci pocztkow, kocow oraz krokiem ptli, np:
Podaj wartosc poczatkowa petli: 1
wolna_linia
Podaj wartosc koncowa petli: 10

Dzieje si tak dlatego, e funkcje typu getxxx musz by zakoczone naciniciem klawisza ENTER, i to wanie powoduje powstanie dodatkowej pustej linii.

9/!Qumf!j!lpotusvldkf!tufsvkdf

266

W poniszym przykadzie, usuniemy te linie. Dodatkowo, spowodujemy, by wybrane liczby


zostay zapisane w jednym rzdzie (a nie w jednej kolumnie, jak w przykadzie pierwszym).
A oto i nasz program po modernizacji:
;*************************************************PROG_027
;Wykorzystanie petli FOR - przyklad 2.
;
;------------------------------------------------;odszukanie i zaladowanie pliku PROG_025.LSP
;
(setq plik (findfile "prog_025.lsp"))
(if plik
(progn ;plik zostal znaleziony
(load plik)
);progn
(progn ;else - nia znaleziono pliku
(alert
(strcat
"Nie znaleziono pliku PROG_025.LSP!!!"
"\nWykonywanie programu przerwane."
);strcat
);alert
(exit)
);progn
);if
;---------;jesli plik prog_025 zostal znaleziony
;wykorzystanie petli for
;
(textpage) ;przejscie na ekran tekstowy
;
(princ "\nPrzyklad wykorzystania petli for.")
;
(initget (+ 1 2 4))
(setq x1 (getint "\nPodaj wartosc poczatkowa petli: "))
;
(initget (+ 1 2 4))
(setq x2 (getint "Podaj wartosc koncowa petli: "))

;
(initget (+ 1 2 4))
(setq x3 (getint "Podaj krok petli: "))

;
(princ
(strcat
"\nWypisywanie od "
(rtos x1 2 0)
" do "
(rtos x2 2 0)
" z krokiem = "
(rtos x3 2 0)
".\n"
);strcat
);princ

267

BvupMJTQ!!qsbluzd{oz!lvst
;
(for 'i x1 x2 x3
'(progn
(princ i)
(princ " ")

);progn
);for i
;
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

Wykonanie powyszego programu moe by nastpujce:


Command: (load "prog_027.lsp")

Przyklad wykorzystania petli for.


Podaj wartosc poczatkowa petli: 1

Podaj wartosc koncowa petli: 10

Podaj krok petli: 2

Wypisywanie od 1 do 10 z krokiem = 2.
1 3 5 7 9
Command:

Omwmy teraz wyrnione linie programu, obrazujce zmiany w stosunku do programu PROG_026:
 Przy wypisywaniu na ekran tekstu "Podaj wartosc koncowa petli:", zosta pominity znak nowej linii, umieszczony na pocztku acucha. Tym samym
zostaa usunita pierwsza wolna linia.
 Przy wypisywaniu na ekran tekstu "Podaj krok petli:", zosta pominity
znak nowej linii, umieszczony na pocztku acucha. Tym samym zostaa usunita druga wolna linia.
 Zamiast funkcji terpri, powodujcej przejcie do nowej linii po wypisaniu
liczby, uywamy instrukcji princ, aby oddzieli od siebie poszczeglne liczby,
wypisywane w jednym rzdzie.

Qs{zlbe!4
Przykad ten pokazuje, jak za pomoc ptli FOR mona tworzy list lub wywietla jej
zawarto.
;*************************************************PROG_028
;Wykorzystanie petli FOR - przyklad 3.
;
;------------------------------------------------;odszukanie i zaladowanie pliku PROG_025.LSP
;
(setq plik (findfile "prog_025.lsp"))

9/!Qumf!j!lpotusvldkf!tufsvkdf
(if plik
(progn ;plik zostal znaleziony
(load plik)
);progn
(progn ;else - nia znaleziono pliku
(alert
(strcat
"Nie znaleziono pliku PROG_025.LSP!!!"
"\nWykonywanie programu przerwane."
);strcat
);alert
(exit)
);progn
);if
;---------;jesli plik prog_025 zostal znaleziony
;wykorzystanie petli for
;
(textpage) ;przejscie na ekran tekstowy
;
(princ "\nPrzyklad wykorzystania petli for.")
;
(initget (+ 1 2 4))
(setq
x1 (getint

268

"\nPodaj liczbe zmiennych do umieszczenia na liscie: "

);getint
);setq
;
(setq lista_1 (list))

;
;pobranie zmiennych i umieszczenie ich na liscie lista_1
(terpri)
(for 'i 1 x1 1

'(progn
;pobranie typu zmiennej
(initget "I R S")
(setq
typ (getkword
(strcat
"\Podaj typ zmiennej numer "
(rtos i 2 0)
" [I - integer, R - real, S - string]: "
);strcat
);getkword
);setq
(setq typ (strcase typ))
;
;pobranie wartosci zmiennej
(princ
(strcat
"Podaj wartosc zmiennej numer "
(rtos i 2 0)
": "

269

BvupMJTQ!!qsbluzd{oz!lvst
);strcat
);princ
(cond
((= typ "I")(setq zmienna (getint)))
((= typ "R")(setq zmienna (getreal)))
((= typ "S")(setq zmienna (getstring T)))
);cond
;
;umieszczenie zmiennej na liscie lista_1
(setq
lista_1 (append lista_1 (list zmienna))
);setq
;
);progn
);for i
;
;wyswietlenie utworzonej listy
(textpage) ;przejscie na ekran tekstowy


(princ lista_1)
(getstring T "\nNacisnij ENTER...")
(princ "\nA oto twoja lista wyswietlona funkcja PRIN1:\n")
(prin1 lista_1)

(getstring T "\nNacisnij ENTER...")
;
;wyswietlenie typu i wartosci poszczegolnych zmiennych
(textpage) ;przejscie na ekran tekstowy
(princ "Typy i wartosci zmiennych na liscie LISTA_1:")
(terpri) ;przejscie do nowej linii
(for 'i 1 x1 1

'(progn
;---------;wyswietlenie numeru zmiennej
(princ
(strcat
"\nZmienna numer "
(rtos i 2 0)
);strcat
);princ
;---------;wyswietlenie typu zmiennej
(setq typ (type (nth (- i 1) lista_1)))
(cond
((= typ 'INT)(setq typ "integer"))
((= typ 'REAL)(setq typ "real"))
((= typ 'STR)(setq typ "string"))
);cond
(princ
(strcat
"\nTyp zmiennej = "
typ
);strcat
);princ
;----------

(princ "Oto twoja lista wyswietlona funkcja PRINC:\n")

9/!Qumf!j!lpotusvldkf!tufsvkdf
;wyswietlenie wartosci zmiennej
(setq wartosc (nth (- i 1) lista_1))
(princ "\nWartosc zmiennej = ")
(if (= typ "string")
(progn
(prin1 wartosc)
);progn
(progn ;else
(princ wartosc)
);progn
);if
;---------;wolna linia pomiedzy poszczegolnymi zmiennymi
(terpri)
;---------);progn
);for i

;
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

Wykonanie programu moe by nastpujce:


Command: (load "prog_028")

Przyklad wykorzystania petli for.


Podaj liczbe zmiennych do umieszczenia na liscie: 3

Podaj typ zmiennej numer 1 [I string]: i

Podaj wartosc zmiennej numer 1:


Podaj typ zmiennej numer 2 [I string]: r

Podaj wartosc zmiennej numer 2:


Podaj typ zmiennej numer 3 [I string]: s

Podaj wartosc zmiennej numer 3:

integer, R - real, S 10

integer, R - real, S 1.25

integer, R - real, S Marek Dudek

Oto twoja lista wyswietlona funkcja PRINC:


(10 1.25 Marek Dudek)
Nacisnij ENTER...

A oto twoja lista wyswietlona funkcja PRIN1:


(10 1.25 "Marek Dudek")
Nacisnij ENTER...

Typy i wartosci zmiennych na liscie LISTA_1:


Zmienna numer 1
Typ zmiennej = integer
Wartosc zmiennej = 10

26:

271

BvupMJTQ!!qsbluzd{oz!lvst
Zmienna numer 2
Typ zmiennej = real
Wartosc zmiennej = 1.25
Zmienna numer 3
Typ zmiennej = string
Wartosc zmiennej = "Marek Dudek"
Command:

Omwmy teraz wyrnione bloki programu:


 Za pomoc funkcji getint, pod zmienn x1 podstawiamy liczb cakowit dodatni, ktra okrela nam liczb zmiennych na tworzonej licie. Funkcja initget
ustawia odpowiednie kryteria, jakie musi spenia wprowadzona liczba. Na koniec, korzystajc z funkcji list, wywoanej bez argumentw, tworzymy pust
list lista_1. Na licie tej bd umieszczone wartoci naszych zmiennych.
 Korzystajc z ptli FOR oraz zmiennej x1, pobieramy typy i wartoci
poszczeglnych zmiennych i umieszczamy ich wartoci na licie lista_1.
Pobranie typu zmiennej odbywa si w nastpujcy sposb:
za pomoc funkcji (initget "I R S") ustalamy sowa kluczowe, jakie
uytkownik moe wprowadzi w odpowiedzi na wywoanie funkcji getkword. Temat pobierania informacji od uytkownika zostanie dokadnie
omwiony w rozdziale 13.
za pomoc funkcji getkword pobieramy odpowied i podstawiamy j pod
zmienn typ.
za pomoc funkcji strcase zmieniamy acuch podstawiony pod zmienn
typ na due litery.
Uywajc nastpnie instrukcji warunkowej cond, w zalenoci od typu zmiennej, wywoujemy funkcj getint, getreal lub getstring, aby pobra odpowiedni
warto zmiennej. Pobrana warto zostaje umieszczona pod zmienn zmienna.
Wywoanie funkcji (getstring T) umoliwia wstawianie spacji w acuchu danych i dopiero nacinicie klawisza ENTER koczy wprowadzanie acucha.
Gdyby funkcja zostaa wywoana jako (getstring), wwczas wprowadzany
acuch nie mgby zawiera spacji (tzn. wprowadzanie acucha koczy nacinicie klawisza ENTER lub klawisza spacji).
Na koniec, uywajc funkcji append oraz list, umieszczamy nasz zmienn na
licie lista_1. Dziaania na listach zostan dokadnie omwione w rozdziale 10.
 Wywietlamy nasz list wykorzystujc funkcje princ oraz prin1. Zauwa
rnic w wywietlaniu danych acuchowych przez te funkcje.
 Uywajc funkcji FOR, wywietlamy poszczeglne zmienne z listy. Dla kadej
zmiennej podajemy jej numer, typ oraz warto. Na uwag zasuguj tutaj dwie
instrukcje: okrelenie typu zmiennej oraz pobieranie kolejnych elementw
z listy.
Typ zmiennej okrelamy za pomoc funkcji AutoLISPu type. Funkcja ta ma
format:
(type item)

9/!Qumf!j!lpotusvldkf!tufsvkdf

272

Przykadowo, jeeli dokonano przypisa:


(setq
a 10
b 1.25
c "To jest string"
d (list 1 2 5)
);setq

wwczas:
(type
(type
(type
(type

a)
b)
c)
d)

zwraca
zwraca
zwraca
zwraca

INT
REAL
STR
LIST

Kolejne elementy z listy pobieramy natomiast stosujc funkcj AutoLISPu (nth n


list). Funkcja zwraca n-ty element argumentu list, gdzie n jest numerem
zwracanego elementu.
Pierwszy element na licie ma numer zero!!! Musisz o tym pamita, by podczas
przegldania poszczeglnych elementw listy nie pomin elementu zerowego
(pierwszego), lub nie prbowa czyta poza ostatnim elementem listy.

W naszym przykadzie, ptla FOR ma budow:


for 'i 1 x1 1

gdzie: x1 liczba zmiennych na licie.


Tak wic, aby pobra kolejne elementy z listy, stosujemy konstrukcj:
(setq wartosc (nth (- i 1) lista_1))

Tak wic, dla i=1, pobieramy zerowy element z listy, a dla i=3, pobieramy drugi
element z listy, itd.

Qs{zlbe!5
W przykadzie tym, wykorzystujemy ptl FOR do obliczenia i wypisania kwadratw
liczb cakowitych od 1 do 10.
;*************************************************PROG_029
;Wykorzystanie petli FOR - przyklad 4.
;
;Program do obliczania kwadratow liczb calkowitych
;od 1 do 10.
;------------------------------------------------;odszukanie i zaladowanie pliku PROG_025.LSP
;
(setq plik (findfile "prog_025.lsp"))
(if plik
(progn ;plik zostal znaleziony
(load plik)

273

BvupMJTQ!!qsbluzd{oz!lvst
);progn
(progn ;else - nia znaleziono pliku
(alert
(strcat
"Nie znaleziono pliku PROG_025.LSP!!!"
"\nWykonywanie programu przerwane."
);strcat
);alert
(exit)
);progn
);if
;------------------------------------------------(textpage) ;przejscie na ekran tekstowy
;---------(princ "\nKwadraty liczb calkowitych od 1 do 10.\n")
(princ "\nLiczba
Kwadrat liczby\n")
(for 'i 1 10 1

'(progn
(setq kwadrat (* i i))

(princ

(strcat
" "
(rtos i 2 0)
"
"
(rtos kwadrat 2 0)
);strcat
);princ
(terpri)
);progn
);for i
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

Wykonanie powyszego programu jest identyczne jak programu PROG_018.


Omwmy teraz wyrnione linie programu:
 Wchodzimy w ptl FOR, ktr wykonamy od 1 do 10 z krokiem rwnym 1.
Prac ptli ma sterowa zmienna i.
 Obliczamy kwadrat danej liczby reprezentowanej przez zmienn i.
 Wykorzystujc funkcje princ, strcat oraz rtos wypisujemy w jednym wierszu
liczb oraz jej kwadrat.

9/6/2/![bhojfe
9/6/2/![bhojfepof!jotusvld
[bhojfepof!jotusvldkf!GPS
pof!jotusvldkf!GPS
Konstrukcja zagniedonych ptli for jest podobna do ptli while czy repeat. Poniej
przedstawiono znany Ci ju program wypisujcy liczby od 1 do 100 w 10 rzdach po 10
kolumn.

9/!Qumf!j!lpotusvldkf!tufsvkdf
;*************************************************PROG_030
;Wykorzystanie zagniezdzonych instrukcji FOR.
;
;Wypisanie liczb od 1 do 100 w 10 rzedach po 10 kolumn.
;
;------------------------------------------------;odszukanie i zaladowanie pliku PROG_025.LSP
;
(setq plik (findfile "prog_025.lsp"))
(if plik
(progn ;plik zostal znaleziony
(load plik)
);progn
(progn ;else - nia znaleziono pliku
(alert
(strcat
"Nie znaleziono pliku PROG_025.LSP!!!"
"\nWykonywanie programu przerwane."
);strcat
);alert
(exit)
);progn
);if
;
;------------------------------------------------(textpage)
;---------(princ "\nWykorzystanie zagniezdzonych instrukcji FOR.")
(princ
(strcat
"\nWypisanie liczb od 1 do 100 "
"w 10 rzedach po 10 kolumn."
);strcat
);princ
(princ "\n\n")
;---------(for 'i 1 10 1

'(progn
;---------(for 'j 1 10 1

'(progn
;---------(princ (+ j (* 10 (- i 1))))

(princ " ")

;---------);progn
);for j
;---------(princ "\n")

;---------);progn
);for i
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

274

275

BvupMJTQ!!qsbluzd{oz!lvst
Wykonanie powyszego programu bdzie identyczne jak programw PROG_019
i PROG_024.
Omwmy teraz wyrnione linie programu.
 Rozpoczynamy zewntrzn ptl FOR. Wykonujemy j 10 razy po zmiennej
i z krokiem 1.
 Rozpoczynamy wewntrzn ptl FOR. Wykonujemy j 10 razy po zmiennej
j z krokiem 1.
 Obliczamy warto liczby do wypisania na ekranie, wykorzystujc zmienne
i oraz j. Obliczon warto podstawiamy jako argument funkcji princ.
 Oddzielamy dwoma spacjami poszczeglne liczby w wierszu.
 Bdc ju poza ptl wewntrzn, przechodzimy do nowego wiersza, aby wypisa kolejne zestawy liczb.

Ptla do while oznacza po angielsku: rb dopki


Poniewa w standardowych funkcjach AutoLISPu nie ma definicji ptli do while ,
budowa oraz dziaanie ptli zostan omwione na podstawie konstrukcji z jzyka C.
Ptla taka ma form:
do instrukcja_1 while wyraenie

Dziaanie ptli jest nastpujce:


Najpierw wykonywana jest instrukcja_1. Nastpnie obliczona zostaje warto wyraenia. Jeli jest ono niezerowe (prawda), to wykonanie instrukcja_1 zostanie powtrzone,
po czym znowu obliczone zostanie wyraenie ... i tak w kko, dopki wyraenie bdzie
rne od zera.
Jak wida, dziaanie tej ptli przypomina ptl while. Rnica polega tylko na tym, e
warto wyraenia obliczana jest nie przed, ale po wykonaniu instrukcja_1. Wynika
std, e instrukcja_1 zostanie wykonana co najmniej raz. Czyli nawet wtedy, gdy
wyraenie nie bdzie nigdy prawdziwe.
Ptl do ... while ... mona zrealizowa w podobny sposb jak ptl for przy
pomocy listy funkcji. Rnica pomidzy AutoLISPem a jzykiem C jest tylko taka, e
w AutoLISPie wyraenie faszywe zwraca nil, a nie zero.

9/!Qumf!j!lpotusvldkf!tufsvkdf
Oto przykad realizacji ptli do ... while ... w jzyku AutoLISP.
;*************************************************PROG_031
;Funkcja DO_WHILE stanowi przyklad realizacji petli
;do (instrukcje) while (warunek) w jezyku AutoLISP.
;
;Funkcja wywolywana jest z dwoma argumentami:
;instrukcje - lista kwotowanych instrukcji do wykonania
;warunek - kwotowany warunek, jaki nalezy spelnic,
;
aby opuscic petle DO_WHILE
;
;Przyklady wywolania funkcji:
;patrz funkcje C:FUN_1 - C:FUN_4
;
;------------------------------------------------;
(defun DO_WHILE (instrukcje warunek
/ jeszcze fun_instrukcje fun_warunek
wartosc
)
(progn
;---------(setq
jeszcze T
fun_instrukcje (list (list '/) instrukcje)
fun_warunek (list (list '/) warunek)
);setq
(while jeszcze
(progn
(FUN_INSTRUKCJE)
(setq wartosc (FUN_WARUNEK))
(if (= wartosc T)
(progn
(FUN_INSTRUKCJE)
);progn
(progn ;else - wartosc = nil
(setq jeszcze nil)
);progn
);if
);progn
);while jeszcze
;---------(princ)
;---------);progn
);DO_WHILE
;
;------------------------------------------------;Funkcja kontrolna C:FUN_1 - uzycie instrukcji DO_WHILE.
;Po wykonaniu funkcji x1 = 1, x2 = 2.
;
(defun C:FUN_1 ()
(progn
(setq
x1 1

276

277

BvupMJTQ!!qsbluzd{oz!lvst
x2 1
);setq
(
DO_WHILE
'(progn ;do
(setq x2 (1+ x2))
);progn
'(progn ;while
(/= x1 1)
);progn
)
(princ)
);progn
);C:FUN_1
;
;------------------------------------------------;Funkcja kontrolna C:FUN_2 - uzycie instrukcji WHILE.
;Po wykonaniu funkcji x1 = 1, x2 = 1.
;
(defun C:FUN_2 ()
(progn
(setq
x1 1
x2 1
);setq
(while (/= x1 1)
(progn
(setq x2 (1+ x2))
);progn
);while
(princ)
);progn
);C:FUN_2
;
;------------------------------------------------;Funkcja kontrolna C:FUN_3 - uzycie instrukcji DO_WHILE.
;Po wykonaniu funkcji x1 = 12.
;
(defun C:FUN_3 ()
(progn
(setq
x1 1
);setq
(
DO_WHILE
'(progn ;do
(setq x1 (1+ x1))
);progn
'(progn ;while
(< x1 11)
);progn
)
(princ)
);progn

9/!Qumf!j!lpotusvldkf!tufsvkdf

278

);C:FUN_3
;
;------------------------------------------------;Funkcja kontrolna C:FUN_4 - uzycie instrukcji WHILE.
;Po wykonaniu funkcji x1 = 11.
;
(defun C:FUN_4 ()
(progn
(setq
x1 1
);setq
(while (< x1 11)
(progn
(setq x1 (1+ x1))
);progn
);while
(princ)
);progn
);C:FUN_4
;
;------------------------------------------------;*************************************************KONIEC

Naley pamita o tym, e zarwno lista instrukcji do wykonania w ptli jak rwnie
warunek wyjcia z ptli musz by poprzedzone apostrofem (tzn. kwotowane) tak
wic ptl DO_WHILE mona przedstawi nastpujco:
(DO_WHILE
'(progn
lista_instrukcji
);progn
'(progn
warunek
);progn
)

Funkcje C:FUN_1 C:FUN_4 pokazuj nam krtkie przykady rozwizania tych


samych zada raz przy pomocy ptli DO_WHILE, drugi raz przy pomocy ptli while.
Na koniec, wykorzystujc ptl DO_WHILE dokonajmy modyfikacji programu do
obliczania kwadratw liczb calkowitych od 1 do 10.
A oto i nasz program po modyfikacji:
;*************************************************PROG_032
;Wykorzystanie funkcji DO_WHILE.
;
;Program do obliczania kwadratow liczb calkowitych
;od 1 do 10.
;------------------------------------------------;odszukanie i zaladowanie pliku PROG_031.LSP
;
(setq plik (findfile "prog_031.lsp"))
(if plik

279

BvupMJTQ!!qsbluzd{oz!lvst
(progn ;plik zostal znaleziony
(load plik)
);progn
(progn ;else - nia znaleziono pliku
(alert
(strcat
"Nie znaleziono pliku PROG_031.LSP!!!"
"\nWykonywanie programu przerwane."
);strcat
);alert
(exit)
);progn
);if
;------------------------------------------------(textpage) ;przejscie na ekran tekstowy
;---------(setq liczba 1)

(princ "\nKwadraty liczb calkowitych od 1 do 10.\n")
(princ "\nLiczba
Kwadrat liczby\n")
(DO_WHILE

'(progn ;do

(setq kwadrat (* liczba liczba))

(princ

(strcat
" "
(rtos liczba 2 0)
"
"
(rtos kwadrat 2 0)
);strcat
);princ
(terpri)
(setq liczba (1+ liczba))

);progn
'(progn ;while

(< liczba 10)

);progn
);DO_WHILE
;---------(princ)
;------------------------------------------------;*************************************************KONIEC

Omwmy teraz wyrnione linie programu:


 Zmiennej liczba nadajemy warto pocztkow 1.
 To tutaj wywoujemy ptl DO_WHILE.
 Uywajc nstrukcji grupujcej progn okrelamy pierwszy argument funkcji
DO_WHILE list instrukcji do wykonania.
 Obliczamy kwadrat liczby.
 Wypisujemy w jednym wierszu liczb oraz jej kwadrat.

9/!Qumf!j!lpotusvldkf!tufsvkdf

27:

 Zwikszamy warto zmiennej liczba o 1.


 Uywajc instrukcji grupujcej progn okrelamy drugi argument funkcji
DO_WHILE warunek wyjcia z ptli.
 Warunkiem wyjcia z ptli jest, by zmienna liczba bya mniejsza od 10 (w tym
samym zadaniu z wykorzystaniem ptli while warunkiem wyjcia z ptli byo,
by zmienna liczba bya mniejsza od 11).

Pamitasz, mwiem kiedy, e jzyk AutoLISP jest jzykiem o dowolnym formacie.


Wynika z tego take, i nawiasy () w naszych instrukcjach sterujcych moemy stawia
w rnych miejscach.
Oto kilka wariantw:
(while (< i 10)(progn
lista_instrukcji
);progn
);while
(while (< i 10)
(progn
lista_instrukcji
);progn
);while
(while (< i 10)
(progn
lista_instrukcji
);progn
);while

Wszystkie 3 sposoby s jednakowo dobre. Namawiam jednak do przyjcia jednego


standardu.
Dlaczego to takie wane? Ot jednym z najczstszych bdw, jaki popeniaj pocztkujcy programici w AutoLISPie jest zapomnienie o zamkniciu nawiasu. Gdy stosujemy zapis  i  to wyranie widzimy, ktre klamry nale do siebie. W sposobie 
tego nie wida, ale za to jest on o jedn linijk krtszy. Osobicie stosuj zapis  i takiego te zapisu bd uywa w tej ksice.
Problem zamknicia nawiasu otwierajcego mona rozwiza na dwa sposoby:

281

BvupMJTQ!!qsbluzd{oz!lvst
1. W moim edytorze jest komenda, ktra pozwala mi odszuka drugi nawias:
pokazuj nawias lewy (otwierajcy), a edytor odszukuje mi odpowiadajcy mu
nawias prawy (zamykajcy). Jeli nawet pogubi si z tymi nawiasami w dugim
programie, to dziki tej opcji atwo znale bd. Sprawd, czy i w Twoim
edytorze jest podobna komenda.
2. Mam sposb, ktry prawie cakowicie pozwala mi unikn bdu. Pisz
warunek, np. (while (< i 10), przechodz linijk niej, pisz instrukcj grupujc
(progn, przechodz 2 linijki niej, zamykam instrukcj grupujc );progn,
przechodz linijk niej, zamykam warunek );while, wracam 2 linijki wyej i
dopiero przystpuj do pisania listy instrukcji.
3. Poniej przedstawiono przykad zapisu nawiasw dla instrukcji while cyframi
  oznaczono kolejne dziaania:
(while (< i 10)
(progn
lista_instrukcji
);progn
);while







Sposb drugi jest naprawd dobry. Od czasu, gdy go stosuj, nawet kilkakrotne
zagniedanie instrukcji while, if, repeat, for nie jest mi straszne, a liczba nie
zamknitych nawiasw spada prawie do zera. Ale nawet wtedy, gdy jaki nawias nie
zostaje zamknity, szybko odnajduj jego lokalizacj wykorzystujc sposb pierwszy.
Prosz Ci, wyprbuj sposb drugi to naprawd dziaa!!!
A tak na marginesie, instrukcje while, cond i repeat nie wymagaj stosowania instrukcji grupujcych progn ja jednak je stosuj dla zwikszenia czytelnoci programu.
Inaczej ma si sprawa z instrukcj warunkow if.
Przeanalizujmy par przykadw.

Qs{zlbe!2
(setq x 10)
(if (= x 10)
(princ "\nX rowna sie 10.")
);if

W przykadzie tym, w wyraeniu if jest tylko jedna instrukcja  i zostanie ona


wykonana, gdy warunek (= x 10) jest prawdziwy ma warto T.

Qs{zlbe!3
(setq x 10)
(if (= x 10)

9/!Qumf!j!lpotusvldkf!tufsvkdf

282



(progn
(princ "\nX rowna sie 10.")
);progn
);if

W przykadzie tym, w wyraeniu if jest tylko jedna instrukcja  zgrupowana w blok


przy pomocy instrukcji grupujcej . Jak w przykadzie 1, instrukcja  zostanie
wykonana, gdy warunek (= x 10) jest prawdziwy ma warto T.

Qs{zlbe!4
(setq x 5)
(if (= x 10)
(princ "\nX rowna sie 10.")
(princ "\nX nie rowna sie 10.")
);if

;else




W przykadzie tym, w wyraeniu if s 2 instrukcje nie zgrupowane funkcj progn, wobec tego interpreter zakada, e instrukcja  ma zosta wykonana, gdy warunek (= x
10) jest prawdziwy ma warto T, natomiast instrukcja  jest instrukcj typu else,
ktra ma zosta wykonana (i zostaje wykonana), gdy warunek (= x 10) jest faszywy
ma warto nil.

Qs{zlbe!5
(setq x 5)
(if (= x 10)
(progn
(princ "\nX rowna sie 10.")
);progn
(progn ;else
(princ "\nX nie rowna sie 10.")
);progn
);if






W przykadzie tym, w wyraeniu if wystpuj dwa bloki instrukcji. Blok pierwszy


tworzy instrukcja  zgrupowana instrukcj  blok ten ma zosta wykonany, gdy
warunek (= x 10) jest prawdziwy ma warto T. Blok drugi tworzy instrukcja ,
zgrupowana instrukcj  blok ten ma zosta wykonany (i zostaje wykonany), gdy
warunek (= x 10) jest faszywy ma warto nil.

Qs{zlbe!6
(setq x 10)
(if (= x 10)

283

BvupMJTQ!!qsbluzd{oz!lvst
(progn
(princ "\nX rowna sie 10.")
(setq y x)
);progn
(progn ;else
(princ "\nX nie rowna sie 10.")
(setq y 0)
);progn
);if

Przykad ten jest przykadem, gdzie instrukcje grupujce progn staj si koniecznoci.
W obydwu blokach trzeba bowiem wykona wicej ni jedn instrukcj musz one
zatem zosta zgrupowane w jeden blok instrukcj grupujc progn.
Osobicie stosuj zapis z przykadw 2, 4 i 5, nawet wtedy, gdy w wyraeniu if jest
tylko jedna instrukcja. Powd? Przeledmy to na poniszym przykadzie.

Qs{zlbe!7
Zamy, e piszc program zapisujesz nastpujce wyraenie warunkowe:
(if (= x 10)
(setq y 0)
);if

Jak na razie, wszystko jest w porzdku. W wyraeniu if wystpuje tylko jedna


instrukcja podstawiania , ktra ma zosta wykonana, gdy warunek (= x 10) bdzie
prawdziwy. Ty tymczasem zaczynasz pisa dalej. Piszesz kolejne instrukcje, by moe
jeste
ju
w innych funkcjach, kiedy nagle przypominasz sobie, e w powyszym wyraeniu
w przypadku prawdziwoci warunku (= x 10) naley dopisa jeszcze jedn instrukcj
podstawienia (setq z 1.25). Odszukujesz wic powysze wyraenie, dopisujesz szybko
dodatkow instrukcj podstawienia, po czym wracasz w inne miejsce programu i piszesz jego dalszy cig. Gdy nastpnie uruchamiasz program, ze zdumieniem stwierdzasz, e program daje ze wyniki lub komunikaty o bdach. Co si waciwie stao?
Przyjrzyjmy si wyraeniu warunkowemu if po modyfikacji:
(if (= x 10)
(setq y 0)
(setq z 1.25)
);if




W wyraeniu tym chciae, aby obie instrukcje zostay wykonane, gdy warunek (= x
10) bdzie prawdziwy. W rzeczywistoci wykonana zostanie tylko instrukcja . Z
braku instrukcji grupujcej progn instrukcja zostanie wykonana, gdy warunek (= x 10)
bdzie faszywy nie zostanie jednak wtedy wykonana instrukcja . Prawidowy
zapis wyraenia warunkowego if powinien wic wyglda tak:
(if (= x 10)
(progn
(setq y 0)

9/!Qumf!j!lpotusvldkf!tufsvkdf

284

(setq z 1.25)
);progn
);if

Przypominam jeszcze raz:


Zgrupowanie cigu instrukcji instrukcj grupujc progn tworzy blok, ktry zostanie
wykonany w caoci dotyczy to w szczeglnoci wyraenia warunkowego if.
Mimo wszystko zapewne czasem pogubisz si w stawianiu nawiasw. Radz Ci: sprbuj
to zrobi wiadomie po to, by si przekona, jak na to zareaguje interpreter AutoLISPu.
Albowiem jego komunikat o bdzie wcale nie musi mwi o braku nawiasu.

Rozdzia ten zapozna Ci z ptlami i konstrukcjami sterujcymi stosowanymi w jzyku


AutoLISP. Ptle dodaj do programu jeszcze jeden poziom skomplikowania. Trzeba
uwanie przestudiowa i przetestowa algorytm, aby mie pewno, e dziaa waciwie.
Pierwszy krok to podjcie decyzji, z ktrej struktury bdziemy korzysta z ptli
while, do_while, repeat czy for. Najpierw stawiamy sobie pytanie:
Czy wiem, ile razy chc powtrzy ptl lub czy bd to wiedzie po
uruchomieniu programu?
Jeli odpowied brzmi tak, to korzystamy z ptli repeat lub for, a jeli nie
zadajemy sobie drugie pytanie:
Czy chc wykona ptl przynajmniej raz?
Jeli odpowiedzi jest tak, to korzystamy z ptli do_while, a jeli nie to z ptli
while.
Jak widzimy (opierajc si na licznych przykadach zamieszczonych w tym rozdziale),
moe by kilka sposobw na napisanie tego samego programu za pomoc wielu
instrukcji if, zagniedonych instrukcji if, operatorw logicznych and i or, instrukcji
warunkowej cond, ptli while, do_while, repeat czy for. O wyborze takiego czy
innego sposobu decydujemy sami. I nikt nie moe nam powiedzie, e wybrany sposb
jest zy, dopki program wykonuje wszystko, czego od niego oczekujemy.
W nastpnym rozdziale omwimy zastosowanie instrukcji command w programach
lispowych.

285

BvupMJTQ!!qsbluzd{oz!lvst

You might also like