Większość instrukcji wbudowanych została zdefiniowana w plikach w katalogu “compile”: “E_cplus_S_machine.h” oraz “E_cplus_S_language.h”, do których można zajrzeć w przypadku wątpliwości co do parametrów instrukcji. Natomiast tutaj opiszę podstawowe.
Typy danych
Podstawowym typem danych jest N, który reprezentuje liczbę naturalną dla procesora, na którym będzie wykonywany program. Odpowiednikiem N, który pozwala na liczby ujemne, jest S. Istnieją też typy danych stosowane, gdy wymagany jest konkretny rozmiar danych: N64, N32, N16, N8 i S64, S32, S16, S8. Liczba oznacza ilość bitów składającą się na liczbę.
Oprócz tych typów danych jest również typ I, który jest stosowany dla identyfikatorów danych zarządzanych przez menedżerów obiektów.
Pojedynczy znak Unicode reprezentuje typ U, a znak bajtowy – typ C.
Liczbę zmienno‐przecinkową – typ F.
Wartość prawda lub fałsz reprezentuje typ B, gdzie prawda jest równa 1, a fałsz 0.
Wskaźnik do dowolnych danych – typ P, a do danych liczonych bajtowo – typ Pc.
Instrukcje ogólnego stosowania w składni programu
Pętla bezwarunkowa jest zdefiniowana jako O. Wystarczy pisać instrukcje w postaci:
O{ ; if( b_1 ) continue; ; if( b_2 ) break; ; }
Pętla wyliczająca to “for_n” i “for_n_”, w postaci:
for_n( i, n ) { } for_n_( i, n ) { }
Pierwsza deklaruje zmienną “i”, a druga korzysta z już zadeklarowanej. Nie trzeba korzystać z tak zadeklarowanej zmiennej, można definiować za każdym razem nową nazwę zmiennej.
Pętla wylicza wszystkie wartości od 0 do “n − 1”.
Analogicznie istnieją instrukcje “for_n_rev” i “for_n_rev_”, które wyliczają w odwrotnej kolejności: od końca do początku.
Obecne są też instrukcje “for_each” – do wyliczania obiektów menedżera, które omówię w innym wpisie, w szczegółowych opisach.
Instrukcje szczególnego stosowania
Wypisywanie komunikatów
Podsystem OUX zawiera wbudowaną funkcję wypisywania komunikatów linii. Komunikaty linii wypisuje się instrukcją “G_” lub “G”: pierwsza wypisuje synchroniczny komunikat linii, a druga asynchroniczny. Gdy w programie używamy wbudowanego mechanizmu przełączania zadań, to należy używać komunikatów asynchronicznych, w pozostałych przypadkach – synchronicznych.
Komunikat linii rozpoczyna się podaną wyżej instrukcją, a następnie w tej samej linii podaje się dodatkowe instrukcje wypisywania wartości zmiennych. Tak jak w przykładzie poniżej:
G_(); Gd(0); Gs0(s);
Widać, że istnieją odpowiednie instrukcje do wypisywania zawartości zmiennych. Dla zmiennej, a właściwie dowolnej wartości, numerycznej jest to instrukcja “Gd”, dla zmiennej tekstowej jest to “Gs0”.
W komunikacie linii najpierw wypisywany jest tekst, jaki wstawiliśmy jako zmienną, a następnie jego wartość. Jeśli chcemy zapobiec dwukrotnemu wypisaniu stałej tekstowej, to możemy użyć instrukcji “Gs0_”, jak w przykładzie:
G_(); Gs0_( "Hello World" );
Wartości zmiennych numerycznych są wypisywane jako liczby dziesiątkowe, jeśli chcemy wypisać w formacie szesnastkowym (np. wartości zmiennych wskaźnikowych), to należy użyć instrukcji “Gh”.
Zarządzanie pamięcią
Utworzone są skrócone instrukcje odwołania się do menedżera bloków pamięci (obiektu “E_mem_Q_blk”). Nie zastępują one konieczności odwoływania się przez pełne nazwy w przypadku korzystania ze wszystkich funkcji tego menedżera, przez pełne nazwy tych innych funkcji.
Instrukcje “M” i “Mt” przydzielają pamięć z menedżera bloków pamięci odpowiednio: o podanym rozmiarze oraz podaną liczbę bloków o podanym rozmiarze. Tak jak w poniższym przykładzie:
P buffer = M(4096); P table = Mt( 1024, 10 );
Natomiast jeśli mamy zadeklarowaną zmienną wskaźnikową, to bezpiecznie jest i powinno się użyć instrukcji “M_” i “Mt_”, które przydzielają tyle pamięci, jaki rozmiar ma zmienna: albo jeden blok, albo podaną liczbę bloków na tablicę. Tak jak poniżej:
M_( zmienna_wskaznikowa_1 ); Mt_( zmienna_wskaznikowa_2, 10 );
Odpowiednio do przydzielania pamięci istnieje instrukcja do zwalniania tej pamięci: “W”. I przykład poniżej:
W(buffer); W(table); W( zmienna_wskaznikowa );
Nierealizacje
Wszystkie wywołania systemowe twojego systemu operacyjnego powinny być objęte instrukcją nierealizacji, która sprawdza poprawność takiego wywołania i w przypadku błędu wypisuje komunikat linii oraz wykonuje odpowiednią akcję.
Są dwa rodzaje nierealizacji: blokowe oraz zakańczające program. Jak w poniższym przykładzie:
int fd; V1( fd = open( "nazwa pliku", O_RDONLY )) { //Tutaj instrukcje w przypadku błędu. } V1_( fd = open( "nazwa pliku", O_RDONLY ));
Instrukcje nierealizacji rozpoczynają się literą “V”, po której następuje symbol odmiany takiej instrukcji, a następnie w przypadku nierealizacji zakańczających program – znak podkreślenia.
Są następujące odmiany tych instrukcji odpowiadające standardom, pod jakie podpadają wyniki wywołań systemowych w przypadku błędu:
- • “V1”, gdy wywołanie zwraca −1 w przypadku błędu
- • “V0”, gdy wywołanie zwraca 0 w przypadku poprawności
- • “Vp”, gdy wywołanie zwraca wartość różną od 0 w przypadku poprawności
- • “Vr” (z odmianami), gdy wywołanie zwraca wartość “errno”
Ponadto w przypadku, gdy wywołanie systemowe może być przerwane przez sygnał i wrócić z błędem “EINTR”, należy użyć instrukcji z literą “O” następującą po “V”, na przykład:
int fd; VO1( fd = open( "fifo", O_RDONLY )) { //Tutaj instrukcje w przypadku błędu. } VO1_( fd = open( "fifo", O_RDONLY ));
Wtedy wywołanie zostanie automatycznie ponowione.
Instrukcje wbudowane związane z wewnętrznym w programie przełączaniem zadań zostaną omówione w innym wpisie, natomiast w celu poznania wszystkich pozostałych odmian omówionych instrukcji należy zajrzeć do jednego z podanych plików katalogu “compile”.