DZWON

Są tacy, którzy czytają tę wiadomość przed wami.
Zapisz się, aby otrzymywać najnowsze artykuły.
E-mail
Imię
Nazwisko
Jak chcesz przeczytać The Bell
Bez spamu

Ya.P. -sztuczny język opracowany przez osobę w celu ułatwienia procesu rozwiązywania problemu za pomocą komputera. Język ten umożliwia albo opis algorytmu rozwiązania problemu - wtedy jest nazywany zorientowany proceduralnie, czyli postawienie problemu w formie matematycznej - zorientowany na problem.

Języki:

1. Uniwersalne (zadania z dowolnej dziedziny)

2. Specjalistyczne (na wąskim obszarze)

Poziom I.P.

1. Niski (asembler, zasoby symboliczne)

2. Wysoki

Funkcja:istnieje możliwość automatycznego tłumaczenia, tłumaczenia tekstu napisanego w języku PL na logicznie równoważną sekwencję czynności w języku instrukcji maszynowych.

Metodą transmisji:

1. Kompilator

2. Interpretator

3. Generator

Alfabet -ustalony zestaw znaków, z których powinien składać się tekst.

Składnia -system reguł określonych przez dopuszczalne konstrukcje z symboli alfabetu. Próbują to opisać formalnie.

Semantyka - system reguł interpretacji konstrukcji językowych. Opisane ściśle, formalnie, jednoznacznie, ale opisane w dowolnej formie.

3. Sposoby formalnego zdefiniowania składni języka programowania

Składnia \u003d metalanguage + diagramy składniowe

Metalanguage -specjalny ponadjęzyk, który opisuje inny język.

Zestaw znaków Metalanguage:

< > - nawiasy ostre (ująć konstrukcje językowe)

{ } szelki (pojęcia w nich zawarte występują zero lub więcej razy)

nawiasy kwadratowe (załączoną koncepcję można pominąć)

Pionowy pasek(alternatywa, „lub”, | ), ::=, =.

Symbole JPw metajęzyku, symbole terminali.

Zbudowane są symbole alfabetu semantyczne konstrukcje językowe.Najprostsze z nich to słowa języka.

Lexeme -słowo językowe, ciąg znaków, który nie zawiera spacji.

Rodzaje leksemów:

1. Identyfikator - służy do oznaczenia programu lub innych obiektów (należy podać nazwę funkcji, typ itp.)

2. Słowa kluczowe - identyfikatory usług, ustalone w PL; służą do tworzenia kompletnych struktur semantycznych języka, nazywane są propozycjejęzyk.

3. Operator - opis, definicja wymagana do przekazania informacji tłumaczowi. Do opisania czynności używany jest operator; jest to jednostka działania.

Diagram składni -jest to wykres skierowany z jedną krawędzią wejściową i jedną krawędzią wyjściową oraz oznaczonymi wierzchołkami. Diagram składni definiuje język. Łańcuch adnotacji w wierzchołkach dowolnej ścieżki od krawędzi wejściowej do wyjścia jest łańcuchem języka określonego przez diagram składniowy. Dlatego możemy założyć, że diagram składniowy jest jedną z form gramatyki generatywnej języków automatów.



Obiekty programu.

Każdy konstrukt, który ma w sobie znaczenie semantyczne tego języka... Wartość, z którą kojarzone są nie tylko nazwa i wartość, ale także pewien obszar pamięci, w którym przechowywana jest wartość tej wartości.

Wyróżnia się:

1. Stałe - niezmienne wartości.

Stałe nazywane są wyliczeniami wartości w programie. Język programowania C rozróżnia cztery typy stałych: stałe całkowite, stałe zmiennoprzecinkowe, stałe znakowe i stałe łańcuchowe.

2. Zmienne

Jedną z podstawowych koncepcji języka C jest obiekt - nazwany obszar pamięci. Specjalnym przypadkiem obiektu jest zmienna. Charakterystyczną cechą zmiennej jest zdolność kojarzenia różnych wartości z jej nazwą, których całość określa typ zmiennej. Podczas ustawiania wartości zmiennej kod tej wartości jest umieszczany w odpowiednim obszarze pamięci. Dostęp do wartości zmiennej zapewnia w naturalny sposób jej nazwa, a dostęp do sekcji pamięci możliwy jest tylko poprzez jej adres. Każdą zmienną należy zdefiniować przed użyciem jej w programie, tj. pamięć musi być przydzielona dla zmiennej. Rozmiar fragmentu pamięci przydzielonej dla zmiennej i interpretacja zawartości zależą od typu określonego w definicji zmiennej. Zdefiniowane są typy całkowite: char - liczba całkowita o długości co najmniej 8 bitów, short int - short integer, int - integer, long - long integer. Każdy z typy całkowite może być zdefiniowany jako podpisany lub niepodpisany bez znaku. Standard języka wprowadza następujące typy rzeczywiste: float - pojedyncza precyzja, podwójna - podwójna precyzja, długie podwójne - maksymalna precyzja.

3. Funkcje.



Funkcjonować jest nazwaną częścią programu, do której można uzyskać dostęp z innych części programu tyle razy, ile potrzeba. Definicja funkcji określa sekwencję czynności wykonywanych podczas uzyskiwania dostępu do funkcji, nazwę funkcji, treść wyniku (wartość zwracana) oraz zestaw parametrów formalnych, które są zastępowane przy wywołaniu funkcji rzeczywistymi parametrami (argumentami).

Ogólny widok definicji obiektów

Wpisz nazwę [inicjator];

Obiekty klasy statycznej domyślnie otrzymują wartość 0, kl. extern - nie otrzymuj.

Obiekt jest zdefiniowany tylko raz... Z definicji ustawiane są atrybuty obiektu, przydzielana jest dla niego pamięć, nazwa obiektu związana z adresem obszaru pamięci. Jeśli istnieje inicjator, istnieje również wartość początkowa.

Pojęcie typu danych

Rodzaj tego Jest to zbiór informacji o wartości ilości, który pozwala na użycie tej ilości podczas rozwiązywania problemu na komputerze.

Powiązane z typem danych: zestaw predefiniowanych wartości (zakres wartości), zestaw operacji, które można wykonać na wartości tego typu, rozmiar pamięci przydzielonej do przechowywania wartości i strukturę wartości. Struktura wartościdefiniuje klasę typu: prostą lub złożoną. Wartość prosty typ jest niepodzielną całością, wartość typu złożonego składa się z oddzielnych części - elementów o wartości złożonej. Zakres wartości Jest to zakres od wartości minimalnej do maksymalnej, która może być reprezentowana w zmiennej tego typu.

Zmienne można zainicjalizować w miejscu ich deklaracji.

System typów to specjalny system, w którym organizowane są dane wykorzystywane przez rozwiązania aplikacyjne. System typów pozwala na przedstawienie informacji w świecie rzeczywistym w terminach „zrozumiałych” dla Ya.P.

Prosta koncepcja typu.

Prosty typ - typ danych, którego obiekty (zmienne lub stałe) nie mają wewnętrznej struktury dostępnej dla programisty.

Znaczenie jest niepodzielne na żadne części

Operacje na całej wartości jako całości.

Są podzielone na:

Podstawowy - prosty skalarny typ danych, którego wszystkie komponenty są już zdefiniowane przez programistę; o imieniu.

Przedefiniowany przez programistę- Sam programista definiuje zestaw dopuszczalne wartości

Proste typy skalarne, które są predefiniowane w C (zwane typami podstawowymi) to:

- typy całkowite: char, int, long int;

- typy pływające: float, double, long double.

Typ liczby całkowitej char jest również używany do reprezentowania wartości znaków (typów znaków). Typy całkowite mają dwie formy - ze znakiem i bez znaku. W skrócie, podpisany można pominąć.

Składa się z:

zbiór prawidłowych wartości

zestaw poprawnych operacji

rozmiar pamięć o dostępie swobodnymprzeznaczone do przechowywania (char - 1b, int - 2b, long - 4b)

wewnętrzna reprezentacja wartości (dodatnia liczba całkowita - wartość binarna, ujemna - uzupełnienie binarne itp.)

znaczenie struktury

Złożone typy

Skomplikowane (złożony) typ - typ danych, których obiekty (zmienne lub stałe) mają wewnętrzną strukturę dostępną dla programisty.

Typy złożone charakteryzują się tym, że każda wartość tego typu składa się z wielu komponentów (elementów), połączonych niejako w jedną całość, tj. ma złożoną strukturę.

Typ złożony jest tworzony przez przestrzeganie zasad.

1. Element o złożonej strukturze może mieć zarówno strukturę prostą, jak i złożoną. Zatem wartości typów złożonych mają na ogół strukturę hierarchiczną, na najniższym poziomie znajdują się tylko proste elementy typu (w tym przypadku poziom zagnieżdżenia można ograniczyć lub nie).

2. W strukturze złożonej typami wszystkich elementów mogą być: - takie same - jednorodne, - różne - niejednorodne.

3. Liczba elementów konstrukcji może być: - ustalona w okresie użytkowania konstrukcji (konstrukcje o stałych wymiarach lub statyczne); - zmienne, tj. dynamicznie zmieniać się, włączając lub wykluczając elementy w procesie pracy ze strukturą (struktury o zmiennej wielkości lub dynamiczne).

4. Dostęp (dostęp) do elementów konstrukcji może być: - bezpośredni (bezpośredni) - obliczany (według indeksu lub miejsca w konstrukcji) lub nie obliczany (według nazwy elementu); - sekwencyjne - charakterystyka struktur o zmiennej wielkości. Rodzaj obróbki zależy od sposobu, w jaki komponenty są połączone w jedną strukturę.

5. Wartość struktury może być przechowywana w operacyjnej (strukturze wewnętrznej) lub w pamięć zewnętrzna

Tablice, łańcuchy

Typ zwykły (tablica) to typ złożony o jednolitej strukturze o stałym rozmiarze i bezpośrednim dostępie obliczeniowym do elementów. Rozmiar struktury jest ustalany podczas opisywania tablicy. Elementy tablicy zajmują ciągły obszar pamięci, tj. są umieszczone kolejno jedna po drugiej. Elementy tablicy są numerowane począwszy od zera.

Ustawienie zmiennej typu zwykłego (tablicy) ma postać

<спецификация типа> <идентификатор> [<константное выражение>]

Tutaj nawiasy kwadratowe to symbole terminali.

Stała ekspresja określa liczbę elementów w tablicy, więc jego wartość jest liczbą całkowitą.

Identyfikator To nazwa zmiennej typu tablica.

Typ komponentów jest ustawiony specyfikacja typu... Komponenty mogą być dowolnego typu (z wyjątkiem typu pliku). Jeżeli typ elementów jest prosty, to definiowana struktura będzie jednowymiarowa (liniowa), jeśli złożona, to wielowymiarowa (nieliniowa).

Tablica wielowymiarowa Jest tablicą, której elementy są typu array. Ustawianie wielowymiarowej tablicy:

<спецификация типа> <идентификатор> []…

Tutaj K1, K2, ..., Kn są wyrażeniami stałymi. Ponadto K1 ustala rozmiar tablicy według pierwszego wymiaru, K2 - według drugiego wymiaru, a Kn - według n-tego wymiaru. Na przykład opis x definiuje tablicę x składającą się z k1 elementów. Każdy element x jest typu array, składający się z k2 elementów. W przeciwnym razie możemy powiedzieć, że x jest dwuwymiarowa tablica (macierz), gdzie k1 to rozmiar wzdłuż pierwszego wymiaru, tj. liczba wierszy w dwuwymiarowej tablicy - macierz; k2 to rozmiar w drugim wymiarze, tj. liczba kolumn w macierzy. Zatem tablica dwuwymiarowa jest traktowana jako tablica jednowymiarowa, której każdy element jest również tablicą jednowymiarową. Elementy macierzy są przechowywane w pamięci komputera wiersz po wierszu.

Aby odwołać się do elementów tablicy, należy podać nazwę tablicy oraz miejsce (indeks) elementu w strukturze: nazwa tablicy [<индекс>] lub nazwa tablicy [<индекс1>][<индекс2>]…[<индекс n>] odpowiednio dla tablic jednowymiarowych i n-wymiarowych. Indeks jest określany przez wyrażenie, którego wartość musi być liczbą całkowitą i określa numer składnika. Wartość indeksu mieści się w zakresie od zera do rozmiaru tablicy minus jeden.

Jest jeszcze jeden sposób na odwołanie się do elementu tablicy - użycie do tego wskaźnika. Wskaźnik to zmienna, której wartością jest adres innej zmiennej, tj. numer (adres) jednostki pamięci przydzielonej zmiennej. Wskaźnik może odnosić się tylko do obiektów określonego typu. Nazwa tablicy jest stałym wskaźnikiem do pierwszego elementu tablicy.

Smyczki.Wartością typu „string” jest ciąg znaków (słowo „string” jest ujęte w cudzysłów, ponieważ taki typ nie jest jawnie zdefiniowany w C i mówiąc o typie string, mamy na myśli typ danych z właściwościami typu string). Typ „string” (lub po prostu łańcuch) w C jest uważany za podzbiór typu tablicy. Łańcuch jest określany jako jednowymiarowa tablica, której elementami są symbole, ostatni znak tablicy to „\\ 0. Ten znak pusty jest zakończeniem linii. Litera „\\ 0”, podobnie jak inne znaki, jest zawarta w ciągu. Rozmiar ciągu (liczba znaków) jest określany przez rozwiązany problem i jest ograniczony dostępną przestrzenią pamięci.

Ponieważ typ ciągu jest tablicą specjalną, wszystkie właściwości typu zwykłego są zachowywane dla ciągu (tj. Można wykonywać operacje na poszczególnych elementach, które są dozwolone dla typu podstawowego). Możesz pracować z „pustą literą” tak samo, jak z resztą znaków (nie zapominając o jej głównym przeznaczeniu).

Oryginalny tekst jest to z reguły ciąg znaków składający się ze słów oddzielonych ogranicznikami i kończących się znakiem końca tekstu. Przy wyborze struktury danych do wyświetlenia

tekstu należy dążyć do tego, aby tekst zajmował minimalną wymaganą ilość pamięci, a wybrana struktura zapewnia szybki (bezpośredni) dostęp do elementów tekstu, którymi z reguły są jego słowa. Wymagania te spełnia struktura danych - tablica.

Tekst możesz sobie wyobrazić:

Tablica dwuwymiarowa - macierz, której wiersz jest słowem tekstowym, zakończonym znakiem końca wiersza - „\\ 0”. Liczba kolumn jest równa maksymalnej długości słowa plus jeden (znak „\\ 0”). Liczba wierszy jest równa maksymalnej liczbie słów w tekście. Odniesienie do wiersza macierzy to odniesienie do słowa. Aby stworzyć taką strukturę, należy odczytywać tekst znak po znaku, umieszczając każde następne słowo w nowym wierszu macierzy i dodając do słowa znak „\\ 0”.

Jednowymiarowa tablica - ciąg. Taka struktura jest w pełni spójna z zewnętrzną prezentacją tekstu. Rozmiar tablicy jest równy maksymalnej długości tekstu oryginalnego, biorąc pod uwagę

separatory. Aby odnieść się do słowa, konieczne jest sekwencyjne przeszukiwanie znaków tablicy, znajdowanie następnego znaku separatora kończącego bieżące słowo, po którym następuje nowe słowo. Kontynuujemy w ten sposób, aż następne słowo kończy się znakiem końca linii.

9. Niejednolite typy (struktura)

Typ heterogeniczny (struktura, rekord) pozwala konstruować struktury danych o najbardziej arbitralnym charakterze. Służy do reprezentowania obiektów o dość złożonej, niejednorodnej strukturze iz reguły służy do tworzenia różnego rodzaju systemów informacyjnych. Niejednolita wartość składa się ze stałej liczby elementów (pól) różnych typów, więc każdy element musi mieć unikalną nazwę, która jest używana do uzyskiwania dostępu do elementu.

Sam programista opisuje typ niejednorodny (strukturalny), określając jego „strukturę wewnętrzną”: liczbę elementów, ich typ i nazwy. Opis typu heterogenicznego:

struct<имя структурного типа>

{ <определения элементов> };

Tutaj struct - słowo serwisowe - specyfikator typu konstrukcji, <имя структурного типа> - identyfikator typu, dowolnie wybrany przez programistę (<имя структурного типа> można pominąć), <определения элементов> - zbiór jednego lub więcej opisów obiektów, z których każdy określa typ elementu wprowadzanego typu konstrukcji.

Definicja obiektu (na przykład zmiennej) o nazwanym typie struktury ma postać struct<имя структурного типа> < список структур>;

lub<имя структурного типа> < список структур> ; Gdzie< список структур> - lista nazw struktur wybranych przez programistę.

Możesz zdefiniować zmienne typu strukturalnego w tym samym czasie, co deklaracja typu. Definicja obiektu o nienazwanym typie konstrukcji jest następująca:

{ <определения элементов> } < список структур>;

A zatem, struktury (zmienne) nienazwany typ konstrukcji ustalona w tym samym czasie z opisem samego typu. Ta opcja jest używana do pojedynczy definicje konstrukcji. Ponieważ elementy konstrukcji mogą być dowolnego typu, dozwolone jest zagnieżdżanie konstrukcji, tj. element konstrukcji może być inną strukturą. W takim przypadku opis typów konstrukcji należy wykonać w takiej kolejności, aby typ konstrukcji użyty w opisie został wcześniej zdefiniowany.

Po zdefiniowaniu struktura może być zainicjowany... Podczas definiowania obiektu typu konstrukcyjnego jest on alokowany pamięć w takiej ilości, aby można było pomieścić dane wszystkich elementów. Rozmiar pamięci w bajtach przydzielonych dla struktury można uzyskać za pomocą operacji sizeof, na przykład sizeof (struct point). Aby odnieść się do elementów konstrukcji, użyj kwalifikowana nazwa (wyrażenie podstawowe) formularza<имя структуры> . <имя элемента структуры> Tutaj kropka oznacza operację dostępu do elementu konstrukcji, ma najwyższy priorytet. Kwalifikowane nazwy elementów struktury mają wszystkie prawa obiektów odpowiednich typów. Można wykonywać operacje na elementach konstrukcji właściwych dla ich typu.

Struktura może być parametrem funkcji i wartością zwracaną (główną) funkcji.

Wskaźnik

Wskaźnik to zmienna, której wartością jest adres innej zmiennej, tj. numer (adres) jednostki pamięci przydzielonej zmiennej. Wskaźnik może odnosić się tylko do obiektów danego typu (jako identyfikatora można użyć nazwy zmiennej, tablicy, struktury lub literału ciągu). W przypadku, gdy zmienna jest zadeklarowana jako wskaźnik, zawiera adres pamięci, pod którym można znaleźć wartość skalarną dowolnego typu. Deklarując zmienną typu wskaźnik, konieczne jest zdefiniowanie typu obiektu danych, którego adres będzie zawierał zmienną oraz nazwę wskaźnika z poprzedzającą gwiazdką (lub grupą gwiazdek). Format deklaracji wskaźnika:

specyfikator typu [modyfikator] * specyfikator.

Specyfikator typu ustawia typ obiektu i może być dowolnego typu podstawowego, typu struktury, mieszanki (zostanie to omówione poniżej). Określając słowo kluczowe void zamiast specyfikatora typu, można w szczególny sposób odłożyć specyfikację typu, do którego odnosi się wskaźnik. Zmienna zadeklarowana jako wskaźnik do typu void może służyć do odwoływania się do obiektu dowolnego typu. Aby jednak móc wykonywać operacje arytmetyczne i logiczne na wskaźnikach lub na obiektach, na które one wskazują, konieczne jest jednoznaczne określenie typu obiektów podczas każdej operacji. Takie definicje typów można wykonać za pomocą operacji rzutowania.

Deklarując wskaźnik, modyfikatorami mogą być słowa kluczowe const, blisko, daleko, ogromne. Słowo kluczowe const wskazuje, że wskaźnika nie można zmienić w programie. Rozmiar zmiennej zadeklarowanej jako wskaźnik zależy od architektury komputera i używanego modelu pamięci, dla którego program zostanie skompilowany. Wskazuje na różne rodzaje dane nie muszą mieć tej samej długości.

Możesz użyć słów kluczowych blisko, daleko, ogromnie, aby zmienić rozmiar wskaźnika.

Pliki.

Typ pliku To typ, który łączy program z zewnętrznymi urządzeniami komputerowymi. Wartość typu pliku to sekwencja składników o dowolnej długości.

Rozmiar pliku (czyli długość sekwencji) nie jest w żaden sposób określany przy deklarowaniu pliku i jest ograniczony jedynie pojemnością zewnętrznych urządzeń pamięciowych. Flaga końca pliku służy do wskazania końca struktury.

W języku C plik jest postrzegany jako strumień lub sekwencja znaków (bajtów), niezależnie od konkretnego urządzenia, z którym wymieniane są dane. Podczas wymiany ze strumieniem często używana jest pomocnicza sekcja pamięci głównej, zwana buforem strumieniowym (bufor wejściowy, bufor wyjściowy).

Podczas pracy ze strumieniem możesz wykonać następujące czynności:

Otwieranie i zamykanie strumieni;

Przeanalizuj stan dotarcia do końca strumienia (koniec pliku) i błędy we / wy;

Pobierz i ustaw wskaźnik na bieżącą pozycję w strumieniu;

Kontroluj buforowanie strumienia i rozmiar bufora.

Wszystkie operacje we / wy są realizowane przy użyciu funkcji znajdujących się w bibliotece C. Aby korzystać z tych funkcji, musisz dołączyć do programu plik nagłówkowy stdio.h, który zawiera prototypy funkcji I / O, definicje stałych, typów i struktur wymaganych do działania funkcji. Strumień można otworzyć w trybie tekstowym lub binarnym. Zgodnie z tym rozróżnia się pliki tekstowe i binarne.

Podczas otwierania pliku w formacie tekst mode, sekwencja znaków odczytywanych ze strumienia jest w razie potrzeby konwertowana z reprezentacji znakowej na reprezentację wewnętrzną. Na przykład, jeśli z formatted w wodzie odczytywana jest informacja numeryczna, a następnie odczytywana sekwencja znaków jest konwertowana na binarną liczbę całkowitą lub zmiennoprzecinkową zgodnie ze specyfikacją formatu; z formatem wycofanie informacje liczbowe są konwertowane z wewnętrznej reprezentacji liczby na sekwencję znaków reprezentujących liczbę. Sekwencję znaków przechowywanych w pliku tekstowym można podzielić na wiersze. Gdy znak nowego wiersza „\\ n” jest zapisywany w strumieniu tekstowym, jest zastępowany sekwencją znaków CR (powrót karetki) i LR (znak nowego wiersza). Kiedy

czytanie z plik tekstowy sekwencja znaków CR i LR jest konwertowana na pojedynczy znak nowego wiersza „\\ n”.

Jeśli plik nie zawiera informacje tekstowezamiast binarnych nie należy wykonywać żadnych konwersji. Na przykład informacje liczbowe są zapisywane do pliku (a następnie odczytywane) w jego wewnętrznej reprezentacji. Ten plik musi być otwarty jako plik binarny.

Funkcje wymiana formatu są przeznaczone do wprowadzania / wyprowadzania pojedynczych znaków, łańcuchów, liczb całkowitych i liczb rzeczywistych wszystkich typów. Na wejściu dane są umieszczane w buforze, a następnie bajtowo lub w określonych porcjach są przesyłane do programu użytkownika. Gdy dane są wyprowadzane do pliku, są one najpierw gromadzone w buforze, a gdy bufor jest pełny, są zapisywane jako pojedynczy blok do pliku w jednym wywołaniu. Zatem użycie bufora pozwala zmniejszyć liczbę wymian z plikiem. Bufor jest domyślnie przydzielany do programu podczas otwierania pliku.

Funkcja odczytuje sekwencję znaków ze strumienia wejściowego, zaczynając od bajtu wskazywanego przez bieżącą pozycję wskaźnika pliku. Wprowadzanie zatrzymuje się, jeśli napotkany zostanie biały znak lub zostanie odczytana liczba znaków określona w specyfikacji konwersji. Sekwencja odczytywanych znaków jest interpretowana zgodnie z ciągiem formatu ( ciąg formatu oglądane sekwencyjnie od pierwszego do ostatniego znaku) jako reprezentacja znakowa liczby całkowitej lub rzeczywistej albo pojedynczego znaku lub ciągu znaków. Następnie jest konwertowany na reprezentację wewnętrzną i zapisywany do obszaru pamięci wraz z następną zmienną z listy argumentów (wskaźnik na aktualną pozycję pliku jest przenoszony na nową aktualną pozycję zgodnie z liczbą odczytanych bajtów).

Ten proces jest kontynuowany do momentu wyczerpania ciągu formatu lub osiągnięcia końca pliku lub wystąpienia błędu. W pierwszym przypadku funkcja zwraca liczbę obiektów, które otrzymały wartość na wejściu, po osiągnięciu końca pliku zwraca stałą EOF, w przypadku błędu wartość –1.

Funkcja skanuje ciąg formatu od lewej do prawej, wyprowadza wszystkie napotkane dowolne znaki do pliku, gdy napotka specyfikację konwersji, oblicza wartość odpowiedniego wyrażenia z listy argumentów, konwertuje je z reprezentacji wewnętrznej na sekwencję znaków zgodnie ze specyfikacją i wyprowadza ją do bieżącej pozycji pliku. Dla każdego argumentu należy określić jedną specyfikację konwersji. Jeśli jest mniej argumentów niż specyfikacji, wynik zależy

od implementacji języka. Dane wyjściowe kończą się, gdy ciąg formatu zostanie wyczerpany lub wystąpi błąd. Funkcja zwraca liczbę wydrukowanych znaków, a w przypadku błędu liczbę ujemną.

W trybie binarnym można zapisać zawartość dowolnego obszaru pamięci do pliku bez konwersji z reprezentacji wewnętrznej. Zatem forma reprezentacji danych w pamięci i w pliku binarnym jest taka sama. Dlatego podczas odczytu z pliku binarnego nie ma potrzeby konwersji na reprezentację wewnętrzną. Funkcje fread i fwrite służą do wymiany z plikiem binarnym.

Składnia jest sprawdzana na wczesnym etapie tłumaczenia. W interpretowanych językach programowania sprawdzanie składni jest przeprowadzane podczas procesu interpretacji (wykonania) lub podczas wstępnej kompilacji do kodu pośredniego. Ponadto składnię można sprawdzić bezpośrednio podczas edycji kodu źródłowego programów wykorzystujących IDE.

Składnia zapisu funkcji

Składnia zapisu funkcji - formalne zasady, jakie musi spełniać definicja funkcji lub rekord wywołania; forma notacji funkcji. Jeśli składnia funkcji jest nieprawidłowa, kompilator zwróci błąd, a program nie zostanie zbudowany, dopóki błąd nie zostanie naprawiony.

Na przykład błędy składniowe podczas pisania funkcji obejmują:

  • pisownia nazwy funkcji w momencie jej wywołania, która nie odpowiada gramatyce języka (niepoprawna wielkość liter dla języków uwzględniających wielkość liter);
  • używanie literałów podczas wywoływania lub definiowania funkcji, która nie odpowiada gramatyce języka (inne typy nawiasów, separator argumentów);
  • brak typu danych zwracanego przez funkcję (dla tych języków, dla których jest to zdefiniowane przez gramatykę).

Podstawowymi elementami każdego języka programowania są jego alfabet, składnia i semantyka.

Alfabet - zestaw znaków wyświetlanych na urządzeniach drukujących i ekranach i / lub wprowadzanych z klawiatury terminala. Zwykle jest to zestaw znaków Latin-1, z wyjątkiem znaków sterujących. Czasami ten zestaw zawiera niewyświetlalne znaki ze wskazaniem zasad ich zapisywania (łączenia w tokeny).

Słownictwo - zbiór zasad tworzenia łańcuchów symboli (tokenów) tworzących identyfikatory (zmienne i etykiety), operatory, operacje i inne leksykalne składniki języka. Obejmuje to również zarezerwowane (zabronione, słowa kluczowe) słowa języka programowania przeznaczone do oznaczania operatorów, funkcji wbudowanych itp. Czasami równoważne tokeny, w zależności od języka programowania, mogą być oznaczone jednym lub kilkoma znakami alfabetu. Na przykład operacja przypisania wartości w języku C jest oznaczona jako „\u003d”, aw języku Pascal - „: \u003d”. Nawiasy operatora w języku C są określane za pomocą symboli „(” i „)”, aw języku Pascal - przez początek i koniec. Dlatego granica między słownikiem a alfabetem jest bardzo warunkowa, zwłaszcza że kompilator zwykle zastępuje rozpoznane słowa kluczowe kodem wewnętrznym na etapie analizy leksykalnej (na przykład początek - 512, koniec - 513) i dalej traktuje je jako oddzielne znaki.

Składnia - zbiór reguł do tworzenia struktur językowych, czyli zdań języka programowania - bloki, procedury, operatory złożone, operatory warunkowe, operatory pętli itp. Cechą składni jest zasada zagnieżdżania (rekurencyjności) reguł konstruowania struktur. Oznacza to, że element składni języka w swojej definicji zawiera się bezpośrednio lub pośrednio w jednej z jego części. Na przykład w definicji operatora pętli ciało pętli jest operatorem, którego szczególnym przypadkiem jest ten sam operator pętli.

Wymagane jest ścisłe przestrzeganie zasad pisowni (składni) programu. W szczególności Pascal jasno definiuje przeznaczenie znaków interpunkcyjnych. Średnik (;) jest umieszczany na końcu nagłówka programu, na końcu sekcji deklaracji zmiennej, po każdej instrukcji. Możesz pominąć średnik przed słowem End. Przecinek (,) jest separatorem elementów na różnych listach: lista zmiennych w sekcji opisu, lista wartości wejściowych i wyjściowych.

Ścisła składnia w języku programowania jest wymagana przede wszystkim od tłumacza. Tłumacz to program, który jest formalnie wykonywany. Jeśli na przykład przecinek musi być separatorem na liście zmiennych, to każdy inny znak będzie postrzegany jako błąd. Jeśli separatorem instrukcji jest średnik, tłumacz interpretuje jako operator całą część tekstu programu od jednego średnika do drugiego. Jeśli zapomniałeś umieścić ten znak między dwoma dowolnymi operatorami, tłumacz potraktuje je jako jeden, co nieuchronnie doprowadzi do błędu.

Głównym celem reguł składniowych jest nadanie jednoznacznego znaczenia konstrukcjom językowym. Jeśli jakakolwiek konstrukcja może być interpretowana niejednoznacznie, to musi zawierać błąd. Lepiej nie polegać na intuicji, ale nauczyć się reguł języka.

Aby opisać składnię języka programowania, potrzebujesz także jakiegoś języka. W tym przypadku mówimy o metajęzyku („supralanguage”) przeznaczonym do opisu innych języków. Najpopularniejszymi metajęzykami w literaturze programowania są formuły metajęzykowe Backusa-Naura (język BNF) i diagramy składniowe. Język diagramów składniowych jest bardziej wizualny, łatwiejszy do zrozumienia.

W BNF każde pojęcie składniowe jest opisane w postaci formuły składającej się z prawej i lewej części połączonych znakiem :: \u003d, którego znaczenie jest równoważne słowom „z definicji jest”. Po lewej stronie znaku :: \u003d zapisana jest nazwa zdefiniowanego pojęcia (metzmienna), ujęta w nawiasy ostre< >, a po prawej stronie znajduje się formuła lub diagram definiujący cały zestaw wartości, które może przyjmować metzmienna.

Składnię języka opisuje sekwencyjna komplikacja pojęć: najpierw ustala się te najprostsze (podstawowe), potem coraz bardziej złożone, w skład których wchodzą pojęcia poprzednie.

W tej kolejności, oczywiście, ostatecznym pojęciem możliwym do zdefiniowania musi być pojęcie programu.

W rekordach meta-formuł przyjmowane są pewne konwencje. Na przykład wzór BNF definiujący pojęcie „cyfry binarnej” jest następujący:

<двоичная цифра>::=0|1

Ikona „|” jest odpowiednikiem słowa „lub”.

Na diagramach strzałki wskazują kolejność elementów składniowych; symbole obecne w konstrukcji są zakreślone.

BNF opisuje pojęcie „kodu binarnego” jako niepustą sekwencję cyfr binarnych w następujący sposób:

<двоичный код>::=<двоичная цифра>|<двоичный

kod\u003e<двоичная цифра>

Definicja, w której pewne pojęcie jest zdefiniowane sama w sobie, nazywana jest rekurencyjną. Definicje rekurencyjne są typowe dla BNF.

Strzałka wstecz wskazuje wiele powtórzeń. Oczywiście diagram jest bardziej ilustracyjny niż BNF.

Diagramy składniowe zostały wprowadzone przez N. Wirtha i użyte do opisania stworzonego przez niego języka Pascal.

Semantyka - semantyczna treść struktur, zdania języka, analiza semantyczna jest sprawdzianem semantycznej poprawności konstrukcji. Na przykład, jeśli w wyrażeniu używamy zmiennej, to musi być zdefiniowana wcześniej w tekście programu, az tej definicji można uzyskać jej typ. Na podstawie typu zmiennej możemy mówić o dopuszczalności operacji z tą zmienną. Błędy semantyczne występują, gdy operacje, tablice, funkcje, operatory itp. Są używane nieprawidłowo.

składnia programu logika kombinatoryczna

Wykład omawia zagadnienia związane z aparatem pojęciowym, historią rozwoju i możliwościami ekspresyjnymi syntaktycznej reprezentacji teorii formalnych i języków programowania..

Sformalizujmy podstawowe konstrukcje języka programowania SML za pomocą formularzy Backus-Naur lub BNF (historia ich powstania jest opisana we wstępie).

Zdefiniujmy nieformalnie składnię (języka programowania lub teorii matematycznej) jako formę konstrukcji (programów lub teorii) i sposoby ich łączenia. Bardziej precyzyjna definicja składni zostanie sformułowana w dalszej części wykładu.

Zdefiniujmy ściślej pojęcie składni.

Składnia jest rozumiana jako sekcja opisująca formalny język matematyczny lub język programowania, który bada formę, formę i strukturę struktur (bez uwzględnienia ich znaczenia lub praktycznej zastosowania).

Patrząc w przyszłość, zauważamy, że znaczenie konstrukcji języka programowania jest opisywane i badane przez semantykę (która zostanie omówiona w następnym wykładzie), a kwestie i wartość praktycznego zastosowania - przez pragmatykę.

Głównym zadaniem składni jest określenie formy i typu dopuszczalnych konstrukcji językowych. Ten problem można rozwiązać, wymieniając opisy wszystkich konstrukcji językowych. Jednym z mechanizmów takiego opisu jest wspomniany już zapis BNF

Równolegle rozważymy formalizację BNF składni rachunku lambda i języka programowania SML. W tym drugim przypadku ograniczymy się zestaw podstawowy konstrukcje językowe, podkreślające takie podstawowe cechy, jak krotki i wyrażenia let.

Aby dobrze zrozumieć rolę i miejsce składni w badaniu języków programowania, rozważmy uogólniony schemat tłumaczenia kodu źródłowego programu (napisanego na przykład w języku programowania SML) na kod maszynowy.

Podczas tłumaczenia programu w pierwszej kolejności wykonywana jest tzw. Procedura analizy leksykalnej polegająca na wyborze w programie tekstu podstawowych konstrukcji językowych, czyli innymi słowy tokenów (w szczególności nazw zmiennych lub identyfikatorów, specjalnych lub słów kluczowych, wartości stałych, zmiennych itd.).

Po zakończeniu analizy leksykalnej wykonywana jest tzw. Procedura rozbiór gramatyczny zdania tekst programu, czyli sprawdzenie poprawności składni tekstu napisanego w języku programowania. Ta procedura może obejmować wykonanie jakiejś formy sprawdzania poprawności wpisywania.

Wreszcie, jeśli wszystkie konstrukcje językowe występujące w tekście programu są poprawne pod względem składniowym i nie zostały zidentyfikowane niezgodności typów zabronionych z punktu widzenia analizatora poprawności pisania, tekst programu jest konwertowany na kod pośredni (asembler, kod jednej lub innej abstrakcyjnej maszyny ) lub rzeczywisty kod maszynowy.

Rozważmy składnię języka programowania SML w porównaniu ze składnią rachunku lambda.

Dla większej jasności i porównywalności formalizacji składni obu języków (języka formalnej teorii matematycznej i języka programowania) użyjemy jednej notacji, a mianowicie BNF.

Przede wszystkim konieczne jest uzgodnienie oznaczeń.

Rozważmy tradycyjne oznaczenia BNF i wyjaśnijmy znaczenie każdego z nich.

W rzeczywistości BNF to definicje niektórych pojęć poprzez inne. W tym przypadku pojęcia są zawarte w nawiasach kątowych i zastosowano szereg wyspecjalizowanych symboli i konwencji, których istotę wyjaśniono poniżej.

Symbol definiujący „:: \u003d” oddziela definiowaną konstrukcję od wcześniej zdefiniowanych konstrukcji bazowych.

Zdefiniowana konstrukcja jest zapisywana po lewej stronie ":: \u003d" w nawiasach ostrych "<" и ">".

Alternatywy (możliwe warianty) projektów są wymienione pionowo.

Cytowanie (tak jak cytowaliśmy znaki specjalne, umieszczając je w podwójnych cudzysłowach) nie ma oznaczenia.

Zilustrujmy formalizację składni za pomocą notacji BNF, biorąc za przykład systemu formalnego rachunek lambda, który jest nam dobrze znany z poprzednich wykładów.

<выражение> ::= <константа> | <переменная> |

(<выражение> <выражение>) |

l<переменная> . <выражение>

Wyjaśnijmy znaczenie powyższych oznaczeń.

W ten przykład definiuje pojęcie wyrażenia, którego składniową reprezentację można wyrazić w postaci jednej z następujących alternatyw:

  • 1. stałe;
  • 2. zmienna;
  • 3. dwa wyrażenia w nawiasach, tj. znana operacja stosowania wyrażeń lambda;
  • 4. znak l, po którym następuje zmienna, kropka i wyrażenie, tj. znana operacja abstrakcji.

Okazuje się, że składnia języka SML ma szereg oczywistych analogii ze składnią rachunku lambda. Analogie te są nieuniknione zarówno ze względu na funkcjonalny charakter rozważanego języka programowania, jak i na podstawie tego, że język SML został opracowany jako środek dowodzenia twierdzeń, a zatem jego składnia (i patrząc w przyszłość, zauważamy, że semantyka) musi być matematycznie przejrzysta. ...

Aby zilustrować powyższe punkty, rozważ najważniejsze kategorie składniowe języka programowania SML.

W dalszej części opisu nazwiemy rekordem, który łączy wyrażenie języka programowania z nazwą, która je określa w programie (identyfikator).

Termin „zarezerwowany” (lub innymi słowy, słowo usługowe) oznacza konstrukcję językową, która jest jednoznacznie interpretowana jako instrukcja języka programowania (na przykład „jeśli”, „wtedy”, „pozwól”). Przypomnij sobie, że w tym zapisie cytaty są tworzone bez cudzysłowów ani innych znaków ograniczających.

Dowolny tekst objaśniający program nazywany jest komentarzem, który zgodnie ze składnią języka SML powinien być ujęty w ograniczniki postaci „(*” i „*)”.

W szczególności rozważymy strukturę głównych poprawnych składniowo typów wyrażeń językowych.

<выражение> ::= <идентификатор> | <литерал> |

<выражение> <выражение> |

<выражение> <идентификатор> <выражение>

Jak widać z formalizacji BNF, poprawnym składniowo wyrażeniem w języku programowania SML jest:

  • 1. identyfikator (tj. Nazwa zmiennej, stałej, funkcji lub typu, zwykle reprezentowana jako sekwencja alfanumeryczna o ograniczonej długości i rozpoczynająca się od znaku alfabetu), lub
  • 2. literały (literały zostaną omówione w dalszej części wykładu) lub
  • 3. sekwencja dwóch wyrażeń lub
  • 4. ciąg dwóch wyrażeń połączonych identyfikatorem.

Kontynuujmy naszą dyskusję o wyrażeniach.

Oprócz wymienionych alternatyw, składniowo poprawnymi wyrażeniami w języku programowania SML są również:

jeśli<выражение> następnie<выражение>

jeszcze<выражение> |

(<выражение> ... <выражение>) |

pozwolić<описание> w<выражение> koniec |

  • 1. trzy wyrażenia połączone przez zarezerwowane słowa if ("if"), then ("then") i else ("inaczej"), nazywane wyrażeniem warunkowym i faktycznie reprezentujące funkcję predykatu, która implementuje wykonanie drugiego wyrażenia, jeśli pierwsze jest prawdziwe a trzecie inaczej;
  • 2. końcowa sekwencja wyrażeń ujęta w nawiasy (tzw. Krotka) i zastosowana do strukturyzowania danych;
  • 3. opis i wyrażenie, połączone zastrzeżonymi słowami let („put”), in („in”) i end („end”), które określają operację podstawienia opisu do wyrażenia, z uwzględnieniem wszystkich możliwych wystąpień określonego fragmentu opisu;
  • 4. wyrażenie ujęte w nawiasach (jak już wiemy, w rachunku lambda i logice kombinatorycznej operacja ta może być wykonana bez ograniczeń) i służy do jednoznacznego wskazania priorytetu operacji.

Kontynuujmy naszą dyskusję na temat kategorii składniowych języka programowania SML.

Przejdźmy do rozważenia struktury typów poprawnych składniowo opisów obiektów językowych.

Przedstawmy odpowiednią formalizację w zakresie BNF.

<описание> ::=

val< идентификатор > = < выражение > |

zabawa< идентификатор > < идентификатор > =

< выражение > |

lokalny< описание > w<описание> koniec

Jak wynika z przedstawionego BNF, składniowo poprawnymi opisami języka programowania SML są:

  • 1. identyfikator i wyrażenie, połączone zastrzeżonymi słowami val i „\u003d”, które oznaczają powiązanie identyfikatora (zmiennej, stałej lub innego składniowo ważnego obiektu języka programowania) z jednym lub innym wyrażeniem;
  • 2. trzy identyfikatory i wyrażenie, połączone zastrzeżonymi słowami fun i „\u003d”, które oznaczają powiązanie funkcji (oznaczonej pierwszym identyfikatorem) z parametrem (oznaczonym drugim identyfikatorem) z wyrażeniem określającym kolejność obliczania wartości;
  • 3. dwa opisy, połączone zastrzeżonymi słowami local, in i end, które oznaczają lokalną definicję pierwszego opisu w kontekście drugiego.

Kontynuujmy naszą dyskusję na temat kategorii składniowych języka programowania SML.

Przejdźmy do rozważenia struktury składniowo dopuszczalnych opisów typów obiektów językowych.

Przedstawmy odpowiednią formalizację w zakresie BNF.

<тип> :: \u003d int | bool |

<тип> * ... * <тип> |

<тип> -> <тип>

Jak wynika z przedstawionego BNF, składniowo poprawnymi typami języka programowania SML są:

  • 1. wartości całkowite oznaczone int zarezerwowanym słowem;
  • 2. wartości logiczne oznaczone zastrzeżonym słowem bool;
  • 3. krotki - uporządkowane n elementów określonych typów;
  • 4. funkcje - uporządkowane elementy n-ki określonych typów połączone symbolami zastrzeżonymi „-\u003e”.

Rozważmy następujący przykład, aby zilustrować wnioskowanie o typie w SML. Stała typu krotka w postaci (0, false, 1, true) ma typ (int * bool * int * bool).

Zauważ, że warianty typów (1) i (2) są elementarne, podczas gdy (3) i (4) są typami pochodnymi o wyraźnie określonej (lub wywnioskowanej) strukturze, z której pochodzi nazwa „typ strukturalny”.

W trakcie wykładu wspominaliśmy już o takiej kategorii syntaktycznej jak literały, czyli o podstawowych typach SML, składających się z określonych sekwencji znaków.

Rozważmy bardziej szczegółowo cechy składniowe głównych typów literałów.

Przedstawmy odpowiednią formalizację w zakresie BNF.

<литерал> ::= <литерал целого типа> |

<литерал строкового типа> |

<литерал вещественного типа>

Jak wynika z przedstawionego BNF, składniowo poprawne typy literałów w języku programowania SML są następujące:

  • 1. literały całkowite typu int i leżące w zakresie od -230 do +230 (ta ostatnia okoliczność jest związana ze specyfiką reprezentacji danych maszynowych);
  • 2. literały łańcuchowe typu string i reprezentujące alfanumeryczne sekwencje znaków w kodzie formatu ASCII;
  • 3. literały rzeczywiste z typem bazowym real, uogólniona postać postaci M x 10E, gdzie M to mantysa w zakresie od -1 do +1, a E to kolejność w odpowiednim zakresie.

Zwróć uwagę, że znaczenie (tj. Semantyka) literałów jest w pełni określone przez ich leksykalną (a zatem syntaktyczną) reprezentację.

Kontynuujmy naszą dyskusję na temat kategorii składniowych języka programowania SML.

Przejdźmy dalej do rozważenia fundamentalnego z punktu widzenia formalizacji języków programowania funkcyjnego - rachunku lambda - działania aplikacji funkcji.

<выражение> <выражение>

Jak wynika z przedstawionego BNF, dopuszczalna składniowo konstrukcja języka programowania SML, który opisuje działanie aplikacji, bardzo dokładnie koresponduje z opisem działania aplikacji w rachunku lambda.

Zilustrujmy zastosowanie funkcji do argumentu w języku programowania SML następującym przykładem.

Rozważmy funkcję succ zdefiniowaną w definicji

fun succ n \u003d n + 1;

i dodaje jedynkę do argumentu (liczba całkowita).

Dla rozpatrywanej funkcji succ poprawna składniowo aplikacja może mieć postać succ 2 i jest obliczana w trakcie wykonywania programu do wartości 3.

Kontynuujmy naszą dyskusję na temat kategorii składniowych języka programowania SML.

Przejdźmy do rozważenia poprawnych składniowo konstrukcji języka programowania SML, zwanych wyrażeniami warunkowymi.

Oto odpowiednia formalizacja pod względem BNF:

jeśli<выражение> następnie<выражение> jeszcze<выражение>;

Jak widać z formalizacji BNF, poprawne składniowo wyrażenie warunkowe składa się z trzech podwyrażeń połączonych słowami zastrzeżonymi if, then i else, o których wspominaliśmy już na wykładzie.

Dodajmy do powyższego szereg niezbędnych uwag. Po pierwsze, pierwsze wyrażenie musi mieć wartość logiczną. Po drugie, typy drugiego i trzeciego wyrażenia muszą być zgodne. Wreszcie druga część warunku jest opcjonalna.

Zwróć też uwagę, że funkcje porównawcze są wbudowane w SML i wyglądają następująco: "\u003d" (równe), "<" (меньше), ">"(więcej),"<=" (меньше или равно), ">\u003d "(większe lub równe)",<>„(nierówne). Każda z funkcji zwraca wartość logiczną.

Zilustrujmy składnię wyrażenia warunkowego następującym przykładem SML:

jeśli n\u003e \u003d 10 to 1 w przeciwnym razie 0;

Zauważ, że powyższe wyrażenie może służyć do analizowania parametru funkcji, która oblicza na przykład liczbę miejsc dziesiętnych.

Kontynuujmy naszą dyskusję na temat głównych kategorii składniowych języka programowania SML.

Przyjrzyjmy się strukturze poprawnych składniowo konstrukcji znanych jako wyrażenia let.

Oto odpowiednia formalizacja pod względem BNF:

pozwolić<описание> w<выражение> koniec;

Jak widać z formalizacji BNF, poprawne składniowo wyrażenie let składa się z opisu i wyrażenia, połączonych zastrzeżonymi słowami let, in i end.

Jak widać ze składni, wyrażenie let to nic innego jak podstawienie wartości w abstrakcji lambda. Wyrażenia niech są używane w języku programowania SML do wiązania wartości i optymalizacji obliczeń, w szczególności w celu umożliwienia powtarzania obliczeń powtarzających się fragmentów programu.

Zilustrujmy składnię wyrażeń let przykładami z języka programowania SML.

Rozważmy następujące wyrażenia let:

niech val n \u003d 2 na końcu n + 1;

niech k \u003d 9876 * 8765 in (k-1, k, k + 1) end;

Jak widać, pierwsze wyrażenie to nic innego jak podstawienie, które można sformalizować za pomocą wyrażenia lambda w postaci (лx.x + 1) 2. Drugie wyrażenie pozwala zredukować wielokrotne obliczenia uciążliwej operacji (mnożenie) do jednej.

Podczas wykładu wielokrotnie wspominano o koncepcji krotki.

Przyjrzyjmy się bliżej temu bardzo ważnemu (zwłaszcza przy implementacji funkcji) rodzaj struktur składniowych języka programowania SML.

Oto formalizacja składniowo poprawnej reprezentacji krotki w kategoriach BNF:

(<выражение>, ..., <выражение>)

Bazując na typie formalizacji BNF, wyjaśnijmy pojęcie krotki. Krotka to grupa, która składa się z co najmniej dwóch wyrażeń (prawdopodobnie różnych typów) połączonych w odrębną kolekcję.

Zwróć uwagę, że krotki są używane w SML do implementacji funkcji wielomiejscowych (mających więcej niż jeden argument), a bardziej ogólnie w teorii i praktyce programowania w relacyjnych bazach danych (w których dane są reprezentowane w postaci tabel), ponieważ krotka jest w rzeczywistości ciągiem taki stół.

Zilustrujmy składnię konstrukcji krotki przykładami z języka programowania SML:

Przykład 1: (1, 2 * 1, 2 * 2 * 1)

Przykład 2: (1, prawda, 0, fałsz)

Zwróć uwagę, że w przypadku pojedynczego wyrażenia krotka ulega degeneracji do wyrażenia w nawiasach. Oczywiście każde wyrażenie SML można ująć w nawias, na przykład, aby wyraźnie wskazać priorytet aplikacji, operacji arytmetycznych i logicznych.

Doświadczenie zdobyte podczas wykładu w rozważaniu głównych typów struktur składniowych języka SML pozwala przejść do formalnej składni takich podstawowych konstrukcji językowych jak opisy zmiennych i funkcji.

Rozważmy formalizacje poprawnych składniowo opisów zmiennych i funkcji w kategoriach BNF:

<описание> ::=

val<идентификатор> = <выражение>

<описание> ::=

zabawa<идентификатор> <идентификатор> =

<выражение>

Pierwsza definicja to opis zmiennej, druga to funkcja. Ponadto obie definicje mają podobną strukturę.

Zilustrujmy formalne opisy zmiennych i funkcji następującymi przykładami:

Przykład 1. val x \u003d 2;

Przykład 2. zabawny fakt n \u003d

jeśli n<2 then 1

else n * fakt (n - 1);

Przykład 3. fun f (x, y) \u003d x * x + y * y;

Pierwszy z tych przykładów to opis (liczby całkowitej) zmiennej x, drugi to rekurencyjna (do samodzielnego zastosowania) funkcja faktyczna do obliczania silni (iloczyn liczb naturalnych od 1 do n), a trzeci to funkcja dwumiejscowa f, która oblicza sumę kwadratów argumentów.

Podsumowując, zwróć uwagę, że to właśnie wtedy, gdy zaimplementowano ostatnią funkcję, używane są krotki (ponieważ składnia SML w swojej „czystej” postaci, jak wynika z BNF, pozwala na użycie tylko funkcji jednomiejscowych).

Dlatego na tym wykładzie rozważono główne typy struktur składniowych języka SML. Po dyskusji można wyciągnąć następujące wnioski:

  • · Składnia funkcjonalnych języków programowania jest dość zbliżona do składni formalnych teorii, na których są one oparte (w szczególności dotyczy to rachunku lambda i języka SML);
  • · BNF to aktualna i odpowiednia formalizacja składni języka;
  • · Język programowania SML, w przeciwieństwie do wczesnych języków programowania funkcjonalnego, posiada szereg rozbudowanych konstrukcji (krotki, wyrażenia let, itp.).

Formularz Backus-Naur (BNF)

Forma Backus-Naur (BNF) została po raz pierwszy użyta do opisania Algol-60. BNF zasadniczo pokrywa się z notacją gramatyk KS, różniących się jedynie zapisem. Dostępne są następujące metaznaki:

<> - służą do podkreślenia nieterminali - pojęć językowych. | - „lub”. Oddziela alternatywne prawe strony reguł. - „jest z definicji”. Zastępuje strzałkę używaną podczas pisania produkcji gramatyk KS.

Symbole terminali są zapisane tak, jak są, nie ma specjalnych sposobów ich wyodrębniania. Oto przykład definicji BNF wziętych ze specyfikacji Algol-60 - „Wiadomość zmodyfikowana”:

<простое арифметическое выражение> ::= <терм> 1 Ok o operacjach takich jak dodawanie\u003e<терм> | <простое арифметическое выражение> <знак операции типа сложения> <терм> <знак операции типа сложения> ::= + | -

Jak widać, do wyrażania powtórzeń używa się rekurencji, a wszędzie - lewej. BNF był używany przez N. Wirtha przy opisywaniu języka Pascal. Chociaż do notacji dodano meta-boxy (i), oznaczające powtórzenie, są one używane tylko w pojedynczych przypadkach, podczas gdy na przykład gramatyka wyrażeń jest lewostronnie rekurencyjna.

Diagramy składniowe

Diagram składniowy jest grafem skierowanym z jedną krawędzią wejściową i jedną krawędzią wyjściową oraz oznaczonymi wierzchołkami. Diagram składni definiuje język formalny. Łańcuch adnotacji w wierzchołkach dowolnej ścieżki od krawędzi wejściowej do wyjścia jest łańcuchem języka określonego przez diagram składniowy. Dlatego możemy założyć, że diagram składniowy jest jedną z form gramatyki generatywnej języków automatów. Diagramy składniowe i automaty skończone są ściśle powiązane: każdy język automatu jest określony przez diagram składniowy i odwrotnie; z dowolnego diagramu składniowego można zbudować automat skończony (w ogólnym przypadku niedeterministyczny), który rozpoznaje ten sam język, który definiuje diagram.

Po skonstruowaniu odpowiedniego rozpoznającego automatu skończonego ze schematu składniowego, można go zaimplementować sprzętowo lub programowo.

Zatem diagramy składniowe mogą służyć nie tylko do generowania, ale także do rozpoznawania języków automatów. Diagramy stały się popularne po opublikowaniu książki K. Jensena i N. Wirtha „Pascal”. Użyto ich w pierwszej części - „Przewodniku” - kompaktowym podręczniku językowym. Na rys. 3.1 przedstawia jeden z dostępnych tam diagramów.

Rozszerzona forma Backus-Naur

Jak już wspomniano, brak środków do jednoznacznego określenia powtórzeń w zapisie gramatyk formalnych (i BNF) stwarza szereg trudności. Po pierwsze, definicje okazują się trudne do zrozumienia, mało jasne z powodu dużej liczby rekurencji. Po drugie, są problemy z faktem, że gramatyki, które dają odpowiednie drzewa semantyczne, okazują się być rekurencyjne. Opisując Modula-2 i Oberon, N. Wirth użył rozszerzonej formy Backus-Naur (RBNF). Główne modyfikacje dotyczą wprowadzenia nawiasów (i) dla powtórzeń oraz [i] - wskazania opcjonalnego występowania łańcuchów terminali i nieterminali w odpowiednich częściach reguł. Konwencje nazewnictwa terminali i nieterminali również uległy zmianie, co nie jest tak fundamentalne. W przyszłości będziemy używać RBNF. Oto jak jest to zdefiniowane w specyfikacji Oberon-2: Warianty są oddzielone znakiem |. Nawiasy kwadratowe [i] oznaczają, że wyrażenie w nich jest opcjonalne, a nawiasy klamrowe (i) oznaczają, że jest ono powtarzane (prawdopodobnie 0 razy). Znaki nieterminalne zaczynają się od dużej litery (na przykład Operator). Symbole terminala albo zaczynają się małą literą (na przykład id), albo są zapisane w całości wielkimi literami (na przykład początek) lub są ujęte w cudzysłów (na przykład „: \u003d”). Do tego należy dodać, że w roli znaku „jest z definicji” w RBNF używany jest „\u003d”, a każda reguła kończy się kropką. Oto jak można zdefiniować składnię identyfikatora (nazwy) za pomocą RBNF:

Imię \u003d Litera (Litera | Numer).

Jako metajęzyk, RBNF powinien być odpowiedni do opisywania języków o praktycznym znaczeniu. W tym za pomocą RBNF, można określić składnię samego RBNF:

Składnia \u003d (reguła). Rule \u003d Name "\u003d" Expression Expression \u003d Variant (wariant "I"). Opcja - element (element). Element \u003d nazwa | Łańcuch | „(„ Wyrażenie ”)” | "[" Wyrażenie "]" | "(" Wyrażenie ")". String \u003d "" "(znak)" "" | „” ”(symbol)„ ””.

W tych definicjach nie ma rozróżnienia między nazwami oznaczającymi terminale i nieterminale, chociaż nie byłoby trudno sformułować to w RBNF. Nazwy wyróżniające znajdują się poza zakresem składni i mogą być (i są) określane oddzielnie. Dzieje się tak często podczas definiowania języków programowania.

Opisy składni w języku C.

C (ang. C) to ustandaryzowany proceduralny język programowania opracowany na początku lat 70. XX wieku przez pracowników Bell Labs, Kena Thompsona i Denisa Ritchiego, jako ewolucja języka B. C został stworzony do użytku w systemie operacyjnym UNIX. Od tego czasu został przeniesiony na wiele innych system operacyjny i stał się jednym z najczęściej używanych języków programowania. Xi jest ceniony za swoją skuteczność; jest to najpopularniejszy język do budowy oprogramowania systemowego. Jest również często używany do tworzenia programy użytkowe... Chociaż C nie został zaprojektowany dla początkujących, jest często używany do nauki programowania. Później składnia języka C stała się podstawą wielu innych języków. Język C charakteryzuje się zwięzłością, nowoczesnym zestawem konstrukcji sterowania przepływem, strukturami danych i obszernym zestawem operacji.

W słynnej książce B. Kernighana i D. Ritchiego opis składni języka C jest podany w notacji, która jest odpowiednikiem BNF, ale używa innych konwencji nazewnictwa terminali i nieterminali, alternatywnych prawych stron reguł i konstrukcji opcjonalnych. Nieterminale są pisane kursywą, terminale są pisane po łacinie. Alternatywne części reguł są zapisane w kolumnie, po jednej w wierszu lub oznaczone słowami „jeden z” (jeden z). Po częściach opcjonalnych następuje indeks dolny „opt (opcjonalnie) - opcjonalne; „Niezbędne” - w niektórych rosyjskich tłumaczeniach). Lewa strona zasady są zapisane w osobnym wierszu z wcięciem w lewo. Oto przykład definicji konstrukcji C:

Operator złożony (lista opisów opt lista operatorów opt) lista operatorów lista operatorów operator lista

Jak widać, ze względu na brak jednoznacznego sposobu wyrażania powtórzeń definicje obfitują w rekursję. Podobna notacja z niewielkimi zmianami jest używana do opisu składni języków potomnych C: C ++, Java, C #. Oto fragment normy ECMA-334 C #:

Blok: (Statement-listopt) statement-list: instrukcja statement-list statement

Najwyraźniej ta notacja nie ma specjalnej nazwy. I wydaje się co najmniej dziwne. Jest to niewygodne nie tylko do czytania, ale także do przetwarzania na komputerze. Jego użycie w opisywaniu nowych języków jest trudne do wyjaśnienia w czymkolwiek innym niż słabo rozumiana potrzeba podążania za tradycją.

Cechy języka C.

  1. Ma prostą bazę językową, z której wiele podstawowych funkcji zostało przeniesionych do bibliotek, takich jak funkcje matematyczne lub funkcje zarządzania plikami;
  2. Ma orientację w kierunku programowania proceduralnego, zapewniając wygodę używania strukturalnego stylu programowania;
  3. Ma system typów, który zapobiega bezsensownym operacjom;
  4. Używanie preprocesora, na przykład do definiowania makr i dołączania plików źródłowych;
  5. Posiada bezpośredni dostęp do pamięci komputera za pomocą wskaźników;
  6. Ma minimalną liczbę słów kluczowych;
  7. Przekazywanie parametrów do funkcji przez wartość, a nie przez referencję (podczas gdy przekazywanie przez referencję odbywa się za pomocą wskaźników);
  8. Wskaźniki do funkcji i zmiennych statycznych;
  9. Ma zakresy nazw;
  10. Rekordy to zdefiniowane przez użytkownika, zbiorcze typy danych (struktury), którymi można manipulować jako całością;

Przykładowy program w C. „Hello world”

main () (printf ("Witaj świecie! \\ n");) #include int main () (printf ("Witaj świecie! \\ n"); return 0;)

Opisy składni Ada

Ada - język programowania stworzony w latach 1979-1980 w wyniku projektu podjętego przez Departament Obrony USA w celu opracowania ujednoliconego języka programowania dla systemów wbudowanych (czyli systemów sterowania dla zautomatyzowanych kompleksów działających w czasie rzeczywistym). Chodziło przede wszystkim o pokładowe systemy sterowania obiektami wojskowymi (statki, samoloty, czołgi, pociski, pociski itp.). Deweloperzy nie stanęli przed zadaniem stworzenia uniwersalnego języka, dlatego decyzje podejmowane przez autorów Ady należy postrzegać w kontekście specyfiki wybranego obszaru tematycznego. Język został nazwany na cześć Ady Lovelace, a badania przeprowadzone od początku do połowy lat siedemdziesiątych XX wieku wykazały, że jeśli Pentagon używa jednego języka programowania do wszystkich swoich zadań, zamiast około 450 języków i ich dialektów, będzie można uzyskać ogromne oszczędności ( około 24 miliardów dolarów za okres od 1983 do 1999 roku) .Język piekła opiera się na ideach programowania strukturalnego i zapewnia wsparcie dla rozwoju złożonych programów wielomodułowych, wysoki stopień niezależności maszyny i przenośności. Projekt języka koncentrował się przede wszystkim na niezawodności i wydajność - język został stworzony specjalnie z myślą o rozwoju dużych systemy oprogramowania w czasie rzeczywistym dla systemów wbudowanych o wysokich wymaganiach dotyczących niezawodności.

Cechy:

Ada to ustrukturyzowany, modułowy, zorientowany obiektowo język programowania zawierający narzędzia programowania wysokiego poziomu dla procesów równoległych. Składnia Ady jest dziedziczona z języków takich jak Algol czy Pascal, ale została rozszerzona, a także stała się bardziej rygorystyczna i logiczna. Ada jest językiem silnie typizowanym, wyklucza pracę z obiektami, które nie mają typów, a automatyczna konwersja typów jest ograniczona do absolutnego minimum.

Funkcje składni

  1. Programy są modułowe, mechanizm kontroli importu-eksportu opisów pomiędzy modułami zawiera dwie różne dyrektywy: jedna do podłączenia innego modułu (z), druga do importu jego opisów (użytkowania). Możliwa jest również zmiana nazwy modułu podczas importu (zmiana nazwy) - opcja ta pozwala na użycie wygodniejszych identyfikatorów do oznaczenia pakietu.
  2. Pakiety (jeden z typów modułów) mogą zawierać nagłówek i część osobistą - to, co w nich jest, nie jest eksportowane i nie jest dostępne dla innych modułów.
  3. Obsługiwany jest mechanizm uogólnionych (konfigurowalnych) modułów: pakietów, procedur i funkcji, które umożliwiają opisanie uogólnionych algorytmów przetwarzania danych bez określania konkretnego typu.
  4. Zaawansowany system typów, zarówno wbudowany, jak i generowany przez programistę. Istnieje wiele sposobów tworzenia nowych typów, język obsługuje dwie różne koncepcje: „podtyp” i „typ pochodny”. Zmienne typu i podtypu są zgodne, zmienne typu i jego typu pochodnego nie.
  5. Zaawansowane sposoby odwoływania się do procedur i funkcji: obsługa parametrów wejściowych i wyjściowych, przekazywanie parametrów rzeczywistych w dowolnej kolejności ze wskazaniem nazw formalnych, parametry z wartościami domyślnymi.
  6. Obsługiwane jest nadpisywanie procedur, funkcji i operatorów - tworzenie kilku wariantów procedury, funkcji lub operatora o tej samej nazwie, ale różnych podpisach (rodzajach i liczbie parametrów).
  7. Konstrukcje wbudowane w język do obsługi programowania równoległego: obsługiwane są pojęcia „zadania” (fragment programu wykonywany równolegle), „wejście zadania” (sposób synchronizacji i komunikacji równolegle działających zadań); ) istnieje operator SELECT do organizowania warunkowej interakcji między wątkami (wybór równoległego zadania, z którym należy współdziałać, w zależności od gotowości spotkania i innych warunków).

Gramatyki bezkontekstowe języków Ada-83 i Ada-95 są definiowane przy użyciu wariantu BNF, który dodaje notację dla powtórzeń i części opcjonalnych. Nazwy nieterminalne są pisane zwykłą czcionką z podkreśleniem, jeśli nazwa jest złożona, a słowa zastrzeżone - pogrubioną. Ponieważ w Adzie nie są używane ani nawiasy kwadratowe, ani nawiasy klamrowe, ani „|” (są to wszystkie metaznaki), nie ma specjalnego oznaczenia dla terminali. Definicja składni instrukcji if, zaczerpnięta ze standardu Ada-95, wygląda następująco:

If_statement :: \u003d if condition to sequence_of_statements (elsif condition then sequence_of_statements) end if;

Ciekawa i przydatna cecha: reguły składniowe struktur strukturalnych przedstawione są w formie odpowiadającej ich zalecanemu formatowaniu w programach (podział na linie, wcięcia).

Aby sprostać wymaganiom niezawodności, język jest zbudowany w taki sposób, aby w czasie kompilacji wykrywać jak najwięcej błędów. Ponadto jednym z wymagań w rozwoju języka była jak najłatwiejsza czytelność tekstów programowych, nawet kosztem łatwości pisania. Rezultatem tego podejścia była nieco „ciężka” składnia i wiele ograniczeń, których nie ma w większości popularnych języków przemysłowych (C i C ++) i które są często postrzegane przez profesjonalnych programistów jako zbędne, na przykład takie samo mocne pisanie. Doprowadziło to do powstania idei Ady jako złożonego, niejasnego i niewygodnego w użyciu języka.

Przykład programu „Hellow world” w Adzie

z Ada.Text_IO; procedura Hello is use Ada.Text_IO; begin Put_Line ("Witaj, świecie!"); koniec Hello;

Definicja składni dla Cobol i PL / 1

Cobol (COBOL, COmmon Business Oriented Language), język programowania trzeciej generacji (pierwsza wersja w 1959 r.) przeznaczony głównie do tworzenia aplikacji biznesowych Twórcą pierwszego zunifikowanego standardu Cobola była Grace Hopper (babcia Cobola). Do 1997 roku w Cobolu było aktywnych około 240 miliardów linii kodu. Około 90% światowych transakcji finansowych jest przetwarzanych za pomocą kodu Cobol, a 75% przetwarzania danych handlowych odbywa się w Cobolu. Całkowity koszt obecnie używanego kodu Cobol szacuje się na 2 biliony dolarów. Do tej pory miliardy nowych linii kodu są pisane co roku w języku Cobol.

Do opisu języków Cobol i PL / 1 wykorzystano osobliwy system notacji, który jest przykładem wczesnych notacji. Oto przykład - definiowanie formatu czasownika MOVE w języku Cobol:


Słowa serwisowe są podkreślone, nawiasy kwadratowe oznaczają opcjonalne części konstrukcji, a nawiasy klamrowe oznaczają wybór kilku alternatyw, które są zapisane w kolumnie. Jak widać, powtórzenie jest oznaczone wielokropkiem. Ten sam typ formuł został użyty przy definiowaniu języków baz danych.

Cechy języka Cobol

  1. Nieporęczne, szczegółowe
  2. Dobre, nowoczesne narzędzia do pracy ze strukturami danych i plikami, które zapewniły długą żywotność w aplikacjach biznesowych (przynajmniej w USA).
  3. Zapewnia wizualny i dość zwarty zapis algorytmów w postaci niezależnej od konkretnych maszyn zaprojektowanych do rozwiązywania problemów.
  4. Zawiera dużą liczbę poleceń, które są złożonymi kompleksami standardowych podprogramów, które zapewniają rozwiązanie problemów planowania gospodarczego.

Przykładowy program „Hello world” w Cobol

DZIAŁ IDENTYFIKACJI. ID PROGRAMU. WITAJ ŚWIECIE. * DZIAŁ ŚRODOWISKA. * PODZIAŁ DANYCH. * DZIAŁ PROCEDURY. PARA-1. WYŚWIETLACZ „Witaj, świecie.”. * WYJŚCIE Z PROGRAMU.

PL / 1- (PL / I, Język programowania I - „Język programowania numer jeden”) - opracowany w 1964 roku język programowania stworzony dla informatyki naukowej, inżynierskiej i biznesowej. Zawiera tak szeroki zakres konstrukcji składniowych i wbudowanych funkcji, że prawdopodobnie nie ma kompilatora obsługującego wszystkie możliwości języka PL / 1. PL / 1 obsługuje rekurencję i programowanie strukturalne, a jej głównym obszarem zastosowania jest przetwarzanie danych

Podstawowe właściwości PL / 1

  1. Darmowa składnia
  2. Słowa kluczowe i identyfikatory nie uwzględniają wielkości liter
  3. Domyślnie (w klasycznych wersjach mainframe - zawsze) przekazywanie parametrów przez odniesienie
  4. Obsługa złożonych struktur ze związkami (w terminologii Pascal - rekordy z wariantami)
  5. Niezwykle rozbudowany system wbudowanych typów danych, z możliwością niejawnej konwersji pomiędzy większością z nich
  6. Kilka rodzajów alokacja dynamiczna pamięć
  7. Bardzo uogólnione operatory z wieloma odmianami składni
  8. Ściśle zdefiniowana semantyka struktur sterujących
  9. Operacje na tablicach
  10. Zaawansowany mechanizm wyjątkowego stanu
  11. Obsługa wielozadaniowości i asynchronicznych operacji we / wy na poziomie języka
  12. Wsparcie na poziomie języka dla złożonych akcesorów we / wy
  13. Bardzo zaawansowany preprocesor, będący w istocie podzbiorem PL / 1

Przykład programu „Hello world” na PL / 1

Test: opcje procedury (główne); deklaruj My_String char (20) zmienna inicjalizacja ("Witaj świecie!"); umieść listę pominięć (My_String); koniec testu;

Alfabet języka

Oryginalny alfabet PL / 1 zawierał 60 znaków:

$ @ # A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 \u003d + - * / () ,. "% ;: ¬ & |\u003e< _ ? пробел

Można było pracować z bardziej ograniczonym 48-znakowym alfabetem, który nie obejmował:

@ # ; : ¬ & | > < _ ? -

Zamiast brakujących znaków użyto dodatkowych słów kluczowych. We współczesnych wersjach języka można również używać małych liter łacińskich (słowa kluczowe można pisać zarówno dużymi, jak i małymi literami). Zamiast znaku ¬ (negacja), którego nie ma w przenośnym zestawie znaków, użyj ~.

Literatura

  1. Sverdlov S.Z. Języki programowania i metody tłumaczenia: tutorial. - SPb .: Peter, 2007. - 638 str .: chory.

DZWON

Są tacy, którzy czytają tę wiadomość przed wami.
Zapisz się, aby otrzymywać najnowsze artykuły.
E-mail
Imię
Nazwisko
Jak chcesz przeczytać The Bell
Bez spamu