Is Arabic the language of Paradise? Language of Paradise Additional operations for working with data and memory

December 18th is World Arabic Language Day. The holiday was established by the United Nations in 2010 and is one of the six official languages ​​of the UN. According to the latest data, there are 300 million people in the world who speak Arabic and its dialects. Moreover, for 240 million people it is native. The Arabic language and the religion of Islam are inextricably linked. One is unthinkable without the other, because for one and a half millennia, Muslims of the world have been reading prayers in Arabic five times a day. The Holy Quran was revealed on it, and Prophet Muhammad (peace be upon him) spoke.

The Grozny clergy celebrated the significant date in their own way. The imam of the “Heart of Chechnya” mosque, Magomed Dadakhaev, addressed the city residents. He explained the role of the Arabic language in the life of a Muslim:

Without speaking Arabic, a person cannot understand Islam. Therefore, this language has been highly respected among Muslims from time immemorial. A necessary condition for studying the religion of the Prophet (peace be upon him) is the analysis of Arabic texts, almost all of which were written a very long time ago. There are more than 12 million words in modern Arabic (for comparison, there are 131,000 in Russian, and about a million in English...). It is a very rich and complex language. When I studied at an Islamic university in Syria, our teacher, a philologist, gave us the following example: in Arabic, the number of synonyms for just one word “camel” reaches six thousand! Its grammar is also very complex and multifaceted. Studying it requires a fair amount of intellectual and volitional effort. Therefore, among the interpreters of the Koran and Hadith of the Prophet (peace be upon him), there are no amateurs. It is almost impossible to understand the meaning of the sacred text without having a solid Arabic vocabulary and knowledge of the syntax, semantics, and phonetics of this language. Sometimes you meet people who call themselves experts in the Koran. They quote from the Message of the Almighty and give people advice. But if you ask them about the source of knowledge, you get the answer: “I read the translation.” Such people are very dangerous for Islam, since, without knowing what they are doing, they are capable of introducing confusion and inaccuracies in the interpretation of the message of the Almighty. The following teaching methodology is widely practiced in Islamic educational institutions: for several years, elementary students study exclusively Arabic philology. And only after they have sufficiently mastered the required volume of material do they gain access to the study of the Koranic texts. Thus, the Arabic language is a kind of springboard to mastering information about Islam. Moreover, Arabic is the language that the inhabitants of Paradise will speak. Glory to Allah that He created us Muslims! What the beautiful, rich Arabic language has given us to comprehend our will!

1. This is a story about how people stopped understanding each other and numerous languages ​​of the modern world appeared. How popular is this myth among different nations and what are its interpretations?

2. The myth of the Tower of Babel is based not only on the belief that initially all humanity spoke the same language, but also on the fact that this language was “ideal”: the names of objects conveyed their true essence. Do representatives of other cultures share these views and do they believe that their language is closest to the original?

The answer to the first question is offered in the Old Testament's Book of Genesis 11:1-9, which tells that God decided to punish the human race by placing on it the curse of confusion of languages. The answer to the second question can be found in Genesis 2:19. In this part, God brought all the animals and birds to Adam to hear what Adam would call them, and “whatever a man calls every living soul, that is its name.” An impromptu tour of different cultures will allow us to see how these issues are covered. Regarding the first of them, many agree with the Old Testament: the diversity of languages ​​is a punishment from the Lord or, at least, a consequence of some unfavorable factor.

The legend of one of the Australian tribes tells of eating old people. The tribes that ate the body itself spoke a “pure” language, and those who ate internal organs spoke an “impure” language. African Kabyles believe that people began to speak different languages ​​as a result of the conflict. According to a tribe from Assam, the confusion of languages ​​was due to the fact that three children once hunted a rat. One of the Amazonian tribes is of the opinion that God separated people and their languages ​​so that they would become more obedient to Him. Among the indigenous population of America, the Maidu tribe (California), it is believed that initially people spoke the same language, but one day, at a funeral ceremony, the language ceased to be uniform. The Iroquois believe that the separation of languages ​​was due to a family quarrel in which a child was killed. But the assumption that multilingual languages ​​are a curse is not as widespread as it seems. There are many versions in the world according to which the division occurred as a result of natural processes.

The ancient Indian sacred hymn "Rig Veda" mentions that once there was Vak ("word") and the gods divided it into many forms. The peoples of the Indochina Peninsula tell of six races, each of which had its own tongue in the form of a stem climbing out of a gourd. The Quiché tribe (Guatemala) has a myth that people lived together and spoke the same language until they split into groups. Each chose a god for itself and began to speak its own language.

The South American Navajo creation myth tells of the "Changing Woman" and the emergence of real peoples who spoke her language. So, she created neighboring peoples - the Pueblos, Mexican aborigines and others, and they spoke their own languages, spreading them in different directions. In Islam, the Koran teaches that Adam did not make up names or anything else, but was taught everything by Allah. The diversity of languages ​​is absolutely natural and is a manifestation of the power of Allah. All people are capable of understanding the revelations of the Qur'an, no matter what language they are written in.

The mythological system of many peoples of the world has no explanation for the confusion of languages, which is simply taken for granted, and therefore cannot answer our question. However, in almost all cultures of the world there is a mention of an “ideal” language (question 2). Above we mentioned an Australian tribe that believes that some people (who feed on the human body) speak a “pure” language that conveys the true essence of things. According to the ancient Egyptians, the god Ptah gave names to everything, thus language became a gift from the gods. In China, the “correct” language was taught by mythical emperors. The Qur'an views the diversity of languages ​​as divisions of a single language that includes all others.

Everywhere people are trying to understand how the name of an object reveals its essence. It is assumed that either an “ideal” language that describes the true essence of a subject exists today, or it is a thing of the past. The second assumption serves as a prerequisite for the search for truth and harmony in the world. It seems that ideas about the connection of language with the real world and human existence are embedded in our consciousness. In this regard, a question arises, first voiced in Plato’s dialogue “Cratylus” and which has since been the subject of constant debate: is the connection between the name and the objective essence of things natural (arising in the subjective consciousness of the native speaker) or is this connection conditional and accidental?

Language is a sign system that allows you to move from the meaning and meaning of a concept to its designation.

Man is a verbal being and, unlike animals, communicates with his own kind using language. Sometimes they talk about the “language of animals,” but it is clear that such an expression is conditional - in its richness and capabilities, the language of animals is not similar to human. Angels do not need language at all for their communication - it is difficult to imagine them speaking Russian or English.

The functions of language can be different - in addition to transmitting information, it helps to express feelings and assessments.

Can Scripture be translated?

The language of the Church is the language of prayer, worship and Scripture.

In some religions, sacred texts initially exist in one language and are considered fundamentally untranslatable. Thus, the Muslim Koran was originally compiled in Arabic. Moreover, Muslims believe that this is how this book was created at the beginning of time.

Jewish scribes were also inclined towards the idea of ​​the possibility of sacred texts only in Hebrew. This was not the case with Christian Scripture in the first place.

In the 3rd century BC. The so-called “translation of the seventy” was completed - the Septuagint - a translation of the Old Testament into Greek. Moreover, some researchers believe that it was the Septuagint that played the role of Holy Scripture in intertestamental times.

It was the existence of the Septuagint that became the main argument in favor of the fundamental translatability of Scripture. There is, however, an even stronger one. It is now considered proven that Christ spoke Aramaic to the apostles. But the compilers of the Gospels, without doubt, conveyed these conversations in Greek.

Now there is a scientific direction - linguistic reconstructions. Their compilers are trying to understand how these dialogues sounded in the original. But this is still a subject of scientific research.

Is it really in heaven?Cold?

When translating a language into a language, problems sometimes arise because the languages ​​are not grammatically identical. The meanings and shades of words in different languages ​​are also different.

For example, the phrase “paradise is a green and cool place” clearly shows that Scripture was created in countries with a hot climate, where “coolness” is rather pleasant. In Russian such associations would hardly arise. And the verb “chill out” in the sense of “relax”, “have a good time” came into Russian as a tracing paper from Hebrew through Greek.

Did all Slavs understand the Bible?

The Scripture was not brought to our ancestors in Russian. Cyril and Methodius - the Thessaloniki Greeks - developed a new written language based on the spoken language of the Thessaloniki Slavs.

There are many peoples in the world who use languages ​​that do not have a written language. As long as we are talking about everyday life, there are no problems. But, as soon as a religious text or philosophical treatise needs to be translated into such a language, the language needs to be improved, which is what Cyril and Methodius did.

If we assume that it was easier for Slavic tribes several thousand years ago to agree among themselves than for modern Slavic peoples, then we will be right - the languages ​​were closer. But this does not mean that the translation of Scripture made by Cyril and Methodius was more understandable to the people of Kiev and Novgorod - the written literary language was different.

Perhaps this is a feature of the Russian situation, since the Russian literary language is closer to Church Slavonic than to the Moscow dialect. In fact, the entire Church Slavonic language entered Russian as a “high calm”. For example, even modern participles - such as crying, running - are formed precisely according to the Church Slavonic model - in Old Russian it would be “crying”, “running”.

Sometimes the Old Russian analogues were dropped out altogether - “good” and “bologoe” in the name “Bologoe”; “shelom”, which is only in epics, in contrast to “helmet”.

Languages ​​are close and... parallel

In Ancient Rus' there was a situation of diglossia. This is not the same as “bilingualism”. Diglossia is the use of two languages ​​in parallel in society. For example, in the 19th century both Russian and French were used. French was the language of high society, but, in principle, any text could be translated.

In diglossia, languages ​​do not overlap in their sphere of use. They spoke Old Russian, and could write everyday notes in Old Russian. But they prayed in Church Slavonic.

This situation existed before Peter; in the 18th century it gradually collapsed. Now science and literature could develop in Russian, but only prayers still exist in Church Slavonic. Translate the ad into Church Slavonic and it will look like a joke or blasphemy.

Priest or shepherd?

We live in a unique era. In Tsarist Russia the Bible could be read in Russian, in Ancient Rus' it could be heard in Church Slavonic. But the majority of the people were illiterate or not educated enough to read and comprehend Scripture.

In Soviet times, everyone became literate, but there was no text of Scripture.

Now literacy is still preserved and texts are accessible.

In addition to the Scripture itself, we are invited to master a certain number of Slavic texts - from prayers to worship. True, the existing translation into Russian is somewhat difficult to understand. In the 19th century, having no analogues, translators often transferred Slavicisms into translation.

This is how the phrase “I am the good shepherd” was translated into translation. And there are some difficulties here. A literal translation from the Greek would be: “I am a good shepherd,” but such a translation is perceived as low. On the other hand, now the simple listener will perceive the sublime “shepherd” rather as “priest.” However, it must be admitted that a literal translation into Russian of many biblical sayings is impossible - the phrase “through the lips of a child the truth speaks” will not be perceived as a philosophical saying.

But in general, the perception of the Slavic text of the Bible is hindered more by a lack of understanding of the meaning, rather than the words.

A separate difficulty is grammatical structures. For example, there are a number of enhancements that come from Greek. “Forgive sins and trespasses” simply means forgive all sins. Constructions such as “I was angry with anger” and “I loved with love” are similar.

When translating sacred texts into other languages, problems also arise (although the peoples into whose languages ​​the Scriptures have not yet been translated are, perhaps, 5℅ of the Earth's population). That is, the work that Cyril and Methodius did for the Slavs continues.

Cyril and Methodius were not the first - before that there were translations into Ethiopic and Gothic. After Cyril and Methodius, Stefan of Perm translated the Scriptures into the Zyryan language.

Translations sacred and profane

Is every translation considered a sacred text? No, but only to the extent that it is accepted in church communities. For example, the Synodal translation as a liturgical translation is not prohibited, but is not accepted. But it is used as such by Protestants, for example, Russian Baptists.

There are even modern movements of Protestantism that believe that the biblical text should be accessible to everyone. Comics based on biblical stories are also published.

There are no problems with the text of the New Testament - its source is known in Greek. But the basis for the Synodal translation of the Old Testament was the Hebrew text. Fragments from the Greek translation were inserted only when the discrepancies were fundamental.

In the modern version, it would be nice to have two translations - both from the Jewish Masoretic texts and from the Greek. This would be convenient for those who do not know both languages.

Answers on questions

After the speech, Archpriest Alexander was asked several questions:

What language did Adam speak?

- Hard to tell. On the one hand, language changes while it is alive. But no one knows whether this was a new property of languages ​​that appeared after the construction of the Tower of Babel.

But in any case, Adam's language was probably unlike any other existing language, including Hebrew.

Is there currently a debate about translating divine services into Russian?

– This idea was discussed even before the revolution, and was partly compromised by the renovationists. They all did not serve in Russian, but the idea was supported by them.

Translating the Bible into Russian was not easy, although Metropolitan Philaret’s idea that it was necessary to translate from both Hebrew and Greek was a wise decision. Although this did not give us scientific translations from both languages.

There are isolated cases of the use of the Russian language - the prayer of the Optina elders and the akathist “Glory to God for everything” were originally written in Russian.

There are so many other translations, and so many nuances will arise when performing them, that it is easier to slightly Russify the texts than to translate them.

This process has been going on spontaneously for a long time. Sometimes incidents arise: for example, in the “Wedding Rite” the dual number is sometimes unexpectedly replaced by the plural, and in modern akathists it is used inconsistently.

How does Divine Providence participate in the formation of different languages?

– Language exists outside of human will. A person can create Esperanto, but natural languages ​​exist according to their own laws.

Cyril and Methodius translated into Church Slavonic by inspiration from above, but also according to the model that existed at that time.

By inspiration from above, writing the Gospels in Greek, the apostles laid down the idea of ​​​​translatability of the Gospel.

Prepared by Daria Mendeleeva

Photo by Dmitry Kuzmin

QUESTION: Assalamualaikum yeah!

I came across this article. If I'm not mistaken, you wrote the opposite. If it’s not difficult, you can comment on this article again.

Muslim.

Arabic is the language of the Koran. It was chosen among all the languages ​​of the world, and it has extraordinary properties. This language is also the language of the Prophet Muhammad (peace and blessings of Allaah be upon him). This language is rich and none of the world languages ​​can compete with it. It has a spiritual and physical effect on the speaker of the language.

Previously, the Arabs used to organize poetry competitions, but when the Prophet (pbuh) received the Revelation, the Arabs were so amazed at such a wonderful expressiveness of the language, and even some thought that the Quran had a magical effect on a person. If anyone wants to correct one word or letter from the Koran, the entire harmony of the Divine book will be disrupted. Not a single word of the Quran should be changed, otherwise the meaning and phonetics will change.

We know that some words tend to become outdated over time, and we do not use them. And the language of the Koran has not lost its relevance for 1439 years...

I have been teaching the Quran for more than 10 years and to this day I have never seen one of my students ask me the question: “Why do we study the Quran? Where did it come from? What benefits does it have? What makes it different from reading from left to right? Day after day, the number of people wishing to learn the Arabic alphabet and the rules of Tazhuid, in order to then read the Koran from the original, is growing. But few people think about the answer to the above questions. And finally, when I explain to them about the benefits of the Quran, about its benefits, many begin to delve into it.

Arabic has 29 letters. Sounds are formed at the border of the larynx, in the middle of the larynx, chest, between the root of the tongue and the oral cavity. The sounds of the Arabic language “clean” the oral cavity and are less susceptible to diseases. Also, Arabic is a good speech therapist. It cures lisps and incorrect pronunciation of the letter “r”. This language also helps those with visual impairments. Because reading Arabic text from left to right improves a person's visual apparatus and relaxes them. The oval and round shape of letters also has a good effect on the psyche.

All letters of the Arabic alphabet have consonant sounds. There are no special letters to represent vowel sounds. There are short and long vowels. Short vowels are conveyed in writing using vowels - superscript and subscript marks. Also, out of 28 letters, 22 letters are connected on both sides, and 6 letters are connected only on the right.

The Koran has reached us without distortion for 23 years. The Quran is the last Divine book, and after it there will be no other books. It was sent down to all humanity. The laws of the Koran will remain in force until the day of judgment and will not change. The Koran is an eternal, great miracle of the Almighty, given to the Prophet Muhammad (pbuh). Reading the Qur'an is a form of worship. I advise everyone to read this incomparably wonderful book every day and know its meaning. Hurry to learn to read and talk with your Creator. May Allah grant us to be residents of Jannah and speak Arabic, which He Himself chose.

Dilyar Bektaeva,

ustaz Aktobe regional

central mosque "Nur Gasyr"

http://nurgasyr.kz/index.php/ma-alar/1826-yazyk-zhitelej-dzhannata

ANSWER: wa alaikum as salaam brother!

People like her, home-grown and ignorant “false Ustaz”, must be driven away from Muslims so as not to mislead them with her. Since the Aktobe mosque spreads such nonsense and keeps ignorant teachers, perhaps that is why there are so many extremist sectarians in this city. There is not even a remote hint in either the Qur'an or the Sunnah that Arabic will be the common language for all the inhabitants of Paradise. Think for yourself, how will representatives of other nationalities communicate with each other in Paradise if they do not know Arabic?!!

Previously answered a similar question:

Developing adaptive language RAYA of the interactive programming system DSSP Moscow State University Faculty of Computational Mathematics and Cybernetics N.P. Brusentsov, V.B. Zakharov, I.A. Rudnev, S.A. Sidorov, N.A. Chanyshev Moscow, 1987

General description of the language of PARADISE

Purpose and purpose of language development

RAYA (Evolving Adaptive Language) is the base language of the Dialogue Structured Programming System DSSP. Basic means that it is the basis for all further constructions carried out in the DSSP by developing (expanding, strengthening) the basic language and, perhaps, adapting the language means thus created to a specific application. In contrast to so-called high-level languages, PAYA does not provide ready-made data types and operations, but only elements and primitives for efficiently defining the required types. For example, the original data formats are 8-bit byte, 16-bit word, and 32-bit longword, interpreted depending on the operations performed on them as integers, Boolean vectors, character codes, booleans, data and procedure pointers. In this case, it is possible, on the one hand, to manipulate individual bits of bytes and words, and on the other hand, to form composite data units (words of multiple lengths, vectors, arrays, lines of text, etc.), setting for them one or another interpretation introduction of appropriate operations. Thus, real numbers of the required length and range of values, complex numbers and other objects can be introduced, and the version of the language focused on a given application will include objects and tools characteristic of this application and will not include anything that does not apply to it, - the language will be adapted (adapted) for use. The development of DSSP was aimed at creating a widely available and effective microcomputer programming tool, i.e. computers built on microprocessors. An essential feature of microprocessor architecture is the elementary nature of data types and operations, which means, on the one hand, universality, and on the other, labor-intensive programming. Due to their versatility, microprocessors and the microcomputers created on their basis have potentially limitless application possibilities. However, the practical implementation of these capabilities is limited primarily by the complexity of developing the necessary application programs. Moreover, satisfactory application programs can only be created with a deep and subtle knowledge of the specifics of the relevant applications, i.e. They should be developed not just by programmers, but by highly qualified specialists in a particular field. Therefore, the programming system should not only greatly increase the productivity of programmer work, but also be so simple that it can be mastered and effectively used by non-professional programmers.

A radical solution to this problem would seem to be a significant simplification of computer architecture. But, unfortunately, the architecture of microcomputers is developing in the diametrically opposite direction - along the path of increasing complexity and sophistication, so that it is not easy for a professional programmer to master microcomputer assembly language perfectly today. System programming languages ​​such as C or PL/M have reduced the labor intensity of program development to a certain (though far from sufficient) extent, but they can hardly be recommended to people who are not experienced in programming. A widely accessible language should, of course, be simpler and more natural, and should be based on, as far as possible, everyday, familiar ideas about the essence and technique of programming.

In addition to accessibility and a significant reduction in the labor intensity of program development compared to programming in assembly language, DSSP was required to have universality of the language, the same as that of assembly language, high machine efficiency (i.e. compactness and speed of code), reliability of verifiability of the created programs, and their maintainability and modifiability, as well as mobility (portability) of the system and the programs developed in it to machines of different architectures.

Procedural programming

Programming in the PARADISE language is quite similar to such widespread types of human activity as planning and organizing interconnected actions, works, processes or designing complex material objects - machines, units, structures. Like a designer who realizes his idea by aggregating its component parts (blocks, assemblies, parts), the programmer synthesizes the required complex action from simple actions provided by the language. We can also say that programming (design) consists of the gradual decomposition (decomposition) of the object being implemented into smaller and smaller components.

In the language of PARADISE, the main “construct” is a procedure - a named action. The language is based on a limited set of simple procedures (primitives), represented by their own names (notations). For example: + means “add”, NEG means “change sign”, VCTR means “create vector”. In particular, there are primitives: and; (colon and semicolon) allowing you to introduce a new procedure, for example, with the name P, defining it as a sequence of procedures P1, P2, ..., PN in the form

: P P1 P2 ... PN ;

If the procedure P represents the action that the created program should carry out, the construction of this program using the PAYA language means is reduced to the sequential detailing of the procedures P1, P2, ..., PN. This means that each of these procedures must be defined by a sequence of smaller procedures, which are then defined by sequences of even smaller procedures, and so on, until definitions consisting only of primitives are obtained.

This type of program construction, starting from a given goal and gradually breaking down the procedures used to the level of basic language tools, is known as top-down programming. It is the main way to obtain programs in the PARA language for solving individual, well-defined problems. The opposite is bottom-up programming - the construction, based on the basic means of a system language, of gradually enlarged procedures focused on a certain problem area. In this way, the language is developed and adapted to a specific application.

In both cases, careful structuring of the created programs is essential: every program and every part of the program must consist of a small number of separate parts, each of which performs a specific function and allows autonomous verification. With regard to the PARA language, this means, in particular, that procedure definitions should be short: the defining sequence, as a rule, should not contain more than 5-7 terms. Structuring ensures that the program is understandable, verifiable and modifiable, and significantly reduces the complexity of its creation and maintenance.

The above example definition of procedure P is a simplified one. In fact, the defining sequence may contain as members not only procedure names, but also statements (commands) consisting of more than one word. The name of a procedure, when used outside of combination with other words, is a command to execute the procedure designated by it. Procedure name sequence specifies that these procedures are executed in the order in which their names appear one after another (in linear order). To specify other sequences of execution, RAYA provides special words (prefixes) that prescribe the execution of the procedures named in combination with them, depending on the specified condition, as well as repeated (cyclic) execution of the procedure.

For example, the linear sequence P0 P1 causes procedure P0 to be executed and then procedure P1 to be executed. If procedure P1 does not always need to be executed, but only under the condition that a positive number is obtained as a result of executing P0, then instead of P1, write the execution command according to the condition: IF+ P1, i.e. instead of P0 P1 there will be P0 IF+ P1. RAYA includes a set of conditional prefixes that allow you to effectively express execution by condition, as well as a choice of two, three or more procedures.

Repeated execution of a procedure is specified using the RP prefix. Thus, the RP P command causes the execution of procedure P over and over again until conditions are created under which the EX contained in the body of this procedure is triggered - exiting the loop, after which the next command in linear order is executed. The condition for exiting the loop can be, for example, the equality of some variable X to zero, which is expressed as:

A procedure whose name is included in the definition of another procedure is said to be nested within it. A nested procedure, if it is not a primitive, can in turn contain nested procedures, i.e. nesting can be multiple. In addition, the rules of the RAY language do not prohibit the inclusion in the definition of a procedure of its own name or the name of a procedure containing this name, i.e. RAYA allows recursion.

A repeatedly executed procedure can also be nested within a repeatedly executed procedure. In this case, loop nesting occurs. PARA allows multiple nesting of loops.

Linear sequence of commands, nesting, conditional and cyclic nesting of procedures - this exhausts the possibilities of constructing programs in the PARA language. The scarcity, homogeneity and naturalness of these means is the key to the ease of mastering and using the language. At the same time, it is a strict structured programming language, which ensures a significant reduction in development labor intensity and program reliability.

Procedures and data

Everything that has been said so far is a characteristic of the PARA language as a means of prescribing actions, constructing arbitrary actions from a finite set of primitive operations. The other side of the language consists of means of representing objects on which actions are performed - means of representing and organizing data.

An extremely simple data element is a two-valued element - a bit. All other formats and data types are built from bits. In the RAYA language, the basic formats are 8-bit byte, 16-bit word and 32-bit long word. Depending on the operations performed on them, bytes, words and long words allow many interpretations, i.e. can serve as the basis for various types of data. In addition, they are the starting elements for the formation of composite formats and types.

Actually, RAYA does not contain either simple or composite data types - there are only basic formats (byte, word, long word) and tools for constructing composite formats from them: vectors and multidimensional arrays. In this case, the same bytes (words, long words), depending on the operations performed on them, are interpreted as bit vectors, or as signed and unsigned binary integers, or as characters of the input/output alphabet, etc. Data types and their associated constraints and checks can be introduced in problem-specific extensions to the language.

In the base language, the declaration of data names performs only the function of providing access to data by name: the name is associated with the number of memory cells required by the declaration and the mechanism for accessing them. Test and transform operations are not applied directly to named data. These operations are defined on the operand stack, which is a sequence of 32-bit long words (stack elements) that is dynamically modified by adding (pushing) new elements to the end of it, as well as removing elements from the same end (popping from the stack). Items are removed in the reverse order in which they were sent: the last sent is removed first. Data to be tested or converted is sent to the stack, where prescribed operations are performed on it, after which the processing results can be removed from the stack.

For example, if there is a variable X declared as a 32-bit long word, then only two operations can be performed directly on it:

1) pushing its value onto the stack, which occurs automatically every time the name X is mentioned,

2) assigning it to the team! X is the value of the last (top) element removed from the stack.

If, say, you want to double the value of X by adding it to itself, then you can do this by running the following commands one after another:

Two copies of the value X will be pushed onto the stack, then the + command will remove them, add them and push the resulting amount onto the stack, after which the command! X will take this amount and assign its value to the variable X.

The usual recording of the above example in the form X:=X+X for high-level languages ​​is more familiar to the programmer, but it is not a direct reflection of the sequence of commands executed by the processor, but is a kind of mathematical formula. This is convenient when programming computational tasks, however, in the base language, unambiguous correspondence with the commands being executed seems more important, since command-by-command verification of the program can be done directly in the programming language and there is no need to know a language other than the processor language.

But a particularly valuable benefit of stacked data processing is that testing and transformation procedures can be defined and implemented independently of the data to which they are applied. Testing and conversion operations are formulated not in relation to data identifiers (or names of constants and variables, formal parameters), but in relation to stack elements, which must be assigned operand values ​​by the time the operation is executed. For example, the operation of adding two numbers, performed using the + (add) command, consists of taking the top two elements (vertex and subvertex) from the stack as addends, calculating their sum and pushing it onto the stack. To add two numbers, you need to push their values ​​onto the stack and execute the + command, the result will be at the top of the stack.

A test-transformation procedure with an arbitrary number of input and output parameters can be defined in this way simply as a named action (without a list of parameters) performed on a stack containing the argument values, arranged in a prescribed order, and, after execution, the result values. To apply such a procedure to a particular set of specific data, you must push this data in the appropriate sequence onto the stack. Having consumed them, the procedure will leave its results on the stack (also located in a certain sequence).

In other words, procedure names in the RAY language are used in the same way as operation signs and are essentially symbols of operations with an arbitrary number of operands. In accordance with the principle of operation of the stack, operations are written in postfix form, i.e. the name of the operation is placed after the names or values ​​of its operands. For example, if we denote the operation of obtaining the sum of three numbers with the symbol ++, then the sum of the numbers A, 5 and B will be expressed as follows:

It would be possible to establish formal rules of a postfix language and be guided by them when writing programs, but it is easier and more reliable for a person to deal not with the rules, but with the stack processor model, i.e. with a model of the machine for which programs are created and which will execute them. In the case of the PARA language, such a machine is a DSSP processor - a set of equipment and programs that implements the actions prescribed in this language.

DSSP processor

Physically, the DSSP processor can be implemented in the form of a microprocessor of a simple and efficiently programmable architecture that would allow solving the problem of software equipment for microcomputers in the best possible way. But such a microprocessor has not yet been created and its architecture has to be emulated on existing microcomputers in order to improve their programmability. Of course, emulation is associated with costs - it requires memory and computer time, but in the case of emulating a DSSP processor, these costs are relatively small.

From a programmer's point of view, a characteristic of a processor is its architecture, i.e. information about what a given processor is as a data processing tool, what are the possibilities for presenting data at the input and inside the processor, what testing and data conversion operations are available, how the processor’s own memory is organized, as well as access to main and external memory, what are the control tools the course of the program, interaction with the external environment, response to exceptional events, etc. Mastery of architecture is a necessary condition for meaningful (informal) programming, which significantly reduces the number of errors and increases the reliability of programs.

The central link of the DSSP processor is the already mentioned operand stack. Actually, processing is done on the stack and, as a rule, data is sent through the stack. Individual commands and short sequences of commands on the stack can be executed by passing them to the processor input directly from the terminal keyboard. In this case, the DSSP processor simulates the operation of a postfix calculator. Numbers and operation mnemonic codes entered from the keyboard are separated by spaces. The entered text appears as a line on the terminal screen. The signal for the end of the input and the command to the processor “Execute the entered order” is a key press , also denoted , . Numbers arriving at the processor input are stored on the stack, and commands are executed on the stack. The calculation result obtained at the top of the stack can be copied to the terminal screen with the command. (dot).

For example, to evaluate the expression (2-5)*3 and display the result obtained, enter:

2 5 - 3 * .

After pressing the key the processor produces the result, so the entire line will look like

* 2 5 - 3 * . -90

An asterisk at the beginning of a line is issued by the processor as a signal that it is waiting for input.

In the example considered, the processor perceived and processed the input numbers as decimal integers. In reality, when input, these numbers were converted to binary complement code, and when output, they were converted back to the decimal system. The DSSP processor also allows binary, octal and hexadecimal input/output modes. To switch to the desired mode, you must execute one of the commands B2, B8, B10, B16, respectively.

Key presses cause codes to be sent to the processor input, representing the characters indicated on these keys (letters, numbers, punctuation marks, operation symbols). The sequence of characters entered forms an input string - a chain of bytes containing character codes, one byte per character. The maximum length of the input string is 80 liters.

When processing the input string, the processor isolates words in it - combinations of characters separated from each other by spaces, and interprets them. If the word being processed is the name of an operation (procedure) or data known to the processor, then the processor performs the actions that this name should call by definition. If the word is not known to the processor, then it tries to interpret it as a number, taking into account the set I/O mode.

Numbers are words that consist of digits acceptable in a given number system and, perhaps, containing a minus sign as the first letter. In hexadecimal I/O mode, the valid letters, along with numbers, also include the Latin letters A, B, C, D, E, F. The received number is converted to binary two's complement code and pushed onto the operand stack as a 32-bit long word. Moreover, if the value of the number is outside the range of representable values ​​-2147483648: 2147483647, then it is replaced by a value comparable modulo 2**32 from this range.

In the case when the word being processed is not known to the processor and cannot be accepted as a number, the processor displays the message on the terminal screen: “I don’t know”<обрабатываемое слово>" and waits for further instructions to be entered.

Data input in the form of arbitrary text (a sequence of bytes-literals) is made in the form of text literals, which are text enclosed in double quotes, for example: “Text literal”. The arrival of a text literal at the processor input causes the text enclosed between quotes to be written to main memory in the form of a chain of byte-literals. In this case, the address of the first byte and the number of bytes (text length) are pushed onto the stack. A text literal preceded by a dot is perceived by the processor as a command to “show the text between the quotes on the terminal screen.” For example, sending the character combination “No memory” to the input of the processor will cause the message to appear on the screen: No memory.

The code of an individual character is pushed onto the stack as the low byte of the vertex when this character is received at the processor input along with the # sign preceded by it. For example, the character combination #L will send the code of the letter L onto the stack, the character combination #5 will send the code of the number 5. The TOB command to output a byte to the terminal displays the letter whose code is contained in the low byte of the top of the stack.

Even in the mode of direct execution of commands, the DSSP processor far exceeds the capabilities of a conventional calculator, providing the user, in addition to data processing operations, with the means of declaring named data and defining procedures that can then be used along with basic operations. Declaring data names and defining procedures is done using special commands.

For example, to create a 16-bit variable named, say, TEMP, you should type on the keyboard and apply the key to the processor input team

VAR TEMP

Along with the declaration, you can assign an initial value to the variable, for example, 0:

VAR TEMP 0! TEMP

Now the arrival of the name TEMP at the processor input will cause the current value of this variable to be pushed onto the stack, and assignment to it of a new value removed from the stack can be done by the command! TEMP.

A procedure definition is entered by the command: (colon), containing the name of the procedure being defined and a defining chain of commands with a letter; (semicolon) as the end character of the definition. Let us demonstrate the definition and use of procedures using the example of calculating the factorial of a natural number N using the formula

N!=N*(N-1)*(N-2)*...*2*1, i.e. N-1 multiplication.

To obtain the desired result, the FCT procedure must multiply the given number N by successively decreasing numbers, starting from N-1 to 1, i.e. only N-1 times. In PARA language, this is programmed by executing procedure P t times: DO P, where P is the name of the procedure, t is the current value at the top of the stack, indicating how many times procedure P needs to be executed.

Let us assume that before applying the FCT procedure, the number N is pushed onto the stack and is located at its top. To make the procedure more understandable, let us imagine the modified multiplier of the variable K:

We introduce the definition of the FCT procedure in the form:

FCT [N] ! K K K 1- DO F . [N] ;

Comments are given in square brackets, reflecting the current state of the operand stack. Team! K, which starts the defined procedure, assigns the value of the number N taken from the stack to the variable K. Then K is pushed onto the stack twice and by subtracting 1 at the top of the stack, the number of executions of the repeated procedure F is formed, equal to N-1. Next comes the DO F command, which specifies a loop, upon completion of which the top of the stack will contain the desired value of the factorial - N!. Team. (dot) prints a copy of this value to the terminal screen. It remains to define a procedure F that modifies the value of K by subtracting 1 and multiplies the partial result of the calculation R contained on the stack by K:

F [R] K 1- ! K[R]K*;

The correctness of both procedures is checked by executing their definitions command by command, displaying the contents of the operand stack and the value of the variable K on the terminal screen after each command. Upon completion of the FCT procedure, the top of the stack must contain the value N!, and the value of the variable K must be equal to 1.

Verified and corrected (if errors were identified during the verification process) procedures are tested by applying them to individual values ​​of the number N. Since procedure F is embedded in FCT, its testing is carried out automatically during the testing process of the latter. It should be kept in mind that the result values ​​should not exceed the maximum positive number represented in two's complement code as a 32-bit long word: 2147483647, i.e. FCT only produces correct results for N=1, ..., 13.

Using FCT is no different from using the processor's own instructions: to obtain the result, you need to set the value of the operand and enter the name of the procedure:

5 FCT 120

7 FCT 5040

The above implementation of the FCT procedure required the introduction of an auxiliary variable K, but a functionally equivalent procedure can be implemented without an auxiliary variable, using operation C, which pushes a copy of its top onto the stack, and operations E2 and E3, which exchange the top with the second and third elements of the stack, respectively. The definition of this procedure is as follows.

: FCTA [N] C 1- C DO FA D . ;

: FA C E3 * E2 1- ;

The advantage of such a “pure stack” procedure is that it is completely autonomous: just like basic processor stack operations, it is performed only on the operand stack, without requiring any other memory or causing any changes to other processor components.

The names of defined procedures and declared data are entered into the processor dictionary, which establishes a connection between these names and named objects, that is, with procedure bodies located in the main memory and with elements of this memory allocated for storing declared data. When processing the next word from the input stream, the processor looks through the dictionary and, having found a matching word in it, performs the actions associated with this word. If the search is unsuccessful, then, as already mentioned, an attempt is made to numerically interpret the given word, and if this fails, then a message appears that the word is not known to the processor.

As a result of compiling a procedure definition, the name of this procedure and the pointer (address) of its body, which is a sequence of pointers to procedures and data that make up the definition, are entered into the dictionary. In other words, the internal representation of the body of a procedure is obtained by replacing the names of procedures and data in its definition with pointers of the corresponding bodies, which in turn are the same sequences of pointers, and in the case of primitives, chains of machine commands. We call this internal representation of a program procedural code.

When, along with compiling the definition of procedure P, the definitions of all nested procedures previously unknown to the processor are also compiled, a complete hierarchy of pointers is formed, making it possible to execute procedure P by sending only its name to the processor input. At the same time, there is no point in storing the names of nested procedures compiled in connection with the definition of P, if there is no need to access these procedures separately. In a number of cases, it turns out to be advisable to close access to one or another part of the dictionary, leaving, perhaps, the ability to perform only some procedures.

In order to satisfy such requirements, the dictionary is implemented as a set of sub-dictionaries, over which operations are defined that allow creating and destroying sub-dictionaries and their parts, deleting names, closing and opening access to certain sub-dictionaries. Each subdictionary has a name that is used in the commands related to it. Subdictionary names must begin with the letter $, for example: $PRIME, $EDIT, $FLOAT, $TEXTPROC, $GRAPHICS.

The subdictionary $PRIME, containing the basic set of DSSP words, after the processor starts, is open both for access to the words it contains and for addition to new words. New words entered into it, if necessary, can be deleted along with the bodies associated with them using the FORGET $PRIME command. After this, the possibility of further entering words into this subdictionary is ensured by executing the GROW $PRIME command, which allows the $PRIME subdictionary to be expanded again, and everything entered into it can again be deleted with the FORGET $PRIME command, etc. In this mode, DSSP is used when experimenting with small fragments of programs, individual examples, estimates, and also, if necessary, including new words in the $PRIME subdictionary in the order of development of the system language.

In the case of creating a separate program, they create their own sub-dictionary for it, and this is achieved by starting the program text with the command

PROGRAM$<имя программы>

A person perceives this command as a heading, which should be followed by a comment in square brackets, characterizing in a few words the function implemented by the program. For the processor it is equivalent to a sequence of commands

FORGET $<имя>GROW$<имя>

Therefore, each arrival of the program text at the processor input will cause the deletion of its previous version and open the subdictionary, thus cleared, for entering a new version of the program bearing the same name. This is convenient when making corrections to the program being created, as well as when modifying it in the future.

The text of the program being constructed is not entered into the processor input directly from the keyboard, but is generated in the text editor buffer. The E command (Edit) sets the editing mode, in which words typed on the keyboard are no longer perceived by the processor as commands to be executed immediately, but are simply text written to a buffer and simultaneously displayed on the screen. Using special keys that control the movement of the current position indicator (cursor) across the screen, as well as editing commands given by pressing other keys, the entered text can be corrected and changed, making deletions and insertions, moving its fragments from place to place, etc.

Upon completion of entering and editing text, the editor is turned off by pressing the E key simultaneously with (or rather, with the previously pressed) key , and the system goes into the main mode of DSSP commands. A similar action is caused by simply pressing a key . In this mode, the contents of the editor buffer can be output to the processor input with the PF (PerForm - execute) command. In this case, all commands contained in the text will be executed, in particular, the PROGRAM $ command<имя>will delete $ entered into the subdictionary<имя>since the last time this command was executed, the data and procedure names, as well as the corresponding bodies, reopening this subdictionary for growth. The data declaration and procedure definition commands will enter the names they enter, along with pointers to the data designated by those names and the procedure bodies compiled according to the definitions.

Once loading is complete, procedures and data are available for reference by their keyboard names, and the correctness of the program can be verified by executing the procedures in ascending order, i.e. starting with those whose definitions do not contain untested procedures. Before you start checking, it is appropriate to make sure that the program does not use undefined names. The processor displays them on the screen using the UNDEF command. To supplement the program text with definitions of these names, as well as to correct other errors detected during the checking process, you need to use the E command to call the editor and make the appropriate modification of the source program text located in the editor buffer, and then switch the processor to the main mode and load the contents of the buffer with the PF command.

After checking and testing the program, its source text can be copied from the editor's buffer to disk using the OE f command, where f is the name of the file in which the program will be written to disk. In the future, the contents of the file can be loaded onto the processor input with the LOAD f command, and also copied to the editor’s buffer as an addition to the text in it using the IE f command. By default, files have the extension .DSP. The buffer can be cleared first with the KE command. It is also possible to print the contents of the buffer using the LPE command.

After loading a program ready for execution, it is possible to clean the subdictionary created for it $<имя>CLEAR $ command<имя>. By executing this command, the processor removes unfixed names from the named subdictionary, i.e. all names, except those whose definitions are preceded by a fixing prefix:: (two colons). In this case, only the names themselves (dictionary entries) are deleted, and the procedure bodies and data associated with them are saved and accessible during program execution via internal links established during compilation, but they are no longer accessible from the outside. To restore the ability to access from outside, for example, if you need to compile some addition or change, you need to re-download the source code of the program.

Names can be made externally inaccessible without removing them from the dictionary using the SHUT $ command<имя>, which blocks access to all words of the subdictionary named in it. Opening a subdictionary to use its words is done with the USE $ command<имя>. There is also an ONLY $ command<имя>, which closes all subdictionaries except the named one, and the CANCEL command, which cancels this restriction. The listed commands allow you to control the use of the dictionary during compilation and limit the set of names available to the program user to the required minimum.

Searching for a name in the dictionary is done by looking up its words in the reverse order of the order in which they were entered in the dictionary, i.e. starting with the last one entered. Therefore, for a name defined more than once in the dictionary, the latest definition will be valid. If the subdictionary containing this last definition is closed, then the search continues to the first available dictionary entry with the given name and the definition indicated by that entry will be used.

A few words about data input and output. As already mentioned, the processor tries to interpret a word of the executable program that is not found in the dictionary as a number and, if successful, pushes the binary equivalent of this number onto the stack. Entering a number onto the stack can be done with the TIN command, which requires typing the input number on the keyboard. There are also commands that cause a character entered from the keyboard to be pushed onto the stack: TIB - with display, TRB - without displaying this character on the screen. In this case, the character code is represented by the low byte of a 32-bit word pushed onto the stack, the highest 3 bytes of which are equal to zero.

The contents of the top of the stack can be entered respectively as a number or as a letter. The TON command causes the display of the numerical value of the subvertex on the screen in the output field, the width of which is specified by the vertex, in the number representation system established at the time of its execution. The TOB command displays the character whose code is contained in the low byte of the top of the stack. In both cases, the output is accompanied by the arguments being removed from the stack.

The DSSP processor has an apparatus for external and internal (command) interrupts and provides the following means for processing them. The procedure intended to handle an external interrupt is defined in the same way as a normal procedure, but with the prefix INT added before the colon. The name of such a procedure is associated with the address of the interrupt vector with the command:

<адрес вектора>LINK<имя процедуры>

A command interrupt is a named operation that calls a response procedure. The name of this operation is determined by the TRAP command, which associates with it the so-called final response procedure, which is executed if the final response is not replaced by another response procedure using the ON or EON command. All three commands have the same format:

TRAP<имя вызова> <процедура реагирования>

ON<имя вызова> <процедура реагирования>

EON<имя вызова> <процедура реагирования>

The procedure associated with the call name by the EON instruction is executed with a preliminary exit from the body of the procedure containing the EON instruction, and with the value of the operand stack pointer that existed at the time the EON was executed.

RAYA language syntax

The alphabet of the RAY language includes Latin and Russian, lowercase and capital letters, decimal numbers, mathematical and other special characters. The elements (members) of the alphabet are called letters. The external representation of a letter is its printed image (printed sign). Inside the DSSP processor, each printed character is represented by a byte, the value of which is the binary code of this character. The conversion of external representation into internal and vice versa is carried out by an input/output device (keyboard, display, printer). For convenience, the numerical value of the code is expressed in decimal, hexadecimal or octal systems, calling the corresponding number a decimal, hexadecimal or octal code letter.

All objects of the RAYA language are constructed from characters and represent linear chains of characters of finite length, called words. The separator of words following each other is a non-printable character (space). A string of spaces is equivalent to a single space. In addition, the function of a word separator is performed by the command “Go to the beginning of the next line”, indicated on the keyboards of input devices by the symbol or and, along with letters, having an internal representation as a byte code. Thus, there is no need for separating spaces at the beginning and end of the line.

Example words: CLEAR NOP STACK2 & 1+ -366 X Probe.

The DSSP processor distinguishes words by the first seven letters, recognizing them by polyliteral comparison with the words in its dictionary. The dictionary contains words that are names (designations) of the processor's own operations, called basic operations or primitives, and can be replenished with names of objects (data, procedures) defined by the user. Thus, the words contained in the dictionary are either names of actions (operations, procedures) or names of data (constants, variables, arrays).

When an identifiable word is not in the dictionary, the processor tries to assign it to one of the following cases:

    numeric literal, i.e. a sequence of numbers, possibly starting with a minus sign, for example: 0, 4096, -25;

    literal literal: a word beginning with the character #, which causes the processor to receive the immediately following literal as a given code, for example: #A - literal of the capital Latin letter A, #5 - literal of the number 5, # - literal of the space, ## - literal letters #;

    text literal: arbitrary text enclosed in double quotes and separated by word delimiters, for example: "Text", "Input file N3";

    command for displaying a text message: the text of the displayed message, delimited on the left by the character combination dot-double quote and double quote on the right and separated by word delimiters, for example: "Stack is empty";

    comment: arbitrary text enclosed in square brackets and separated by delimiters, for example: .

Literals and the command to display a message on the display act as objects of the DSSP language along with words identified from the dictionary, while comments are completely ignored by the DSSP processor - they are intended for a person, not a machine. If the word is not found in the dictionary and is not related to the listed constructions, the processor displays the message: “I don’t know<неопознанное слово>".

Due to the special meaning attached to the letters #, "and the combination." at the beginning of a word, i.e. after the separator, as well as the letter " before the separator, they should not be used in the specified positions in words defined for inclusion in the dictionary.

The sequence of words at the processor input is interpreted as a sequence of instructions executed by the processor. There are three types of words:

1) performed independently, i.e. representing single-word commands (monowords);

2) performed in conjunction with one or more subsequent words, i.e. being the initial words (prefixes) of two-, three-, or multi-word commands;

3) preceding a command as a clarification or indication of a special execution mode (preprefixes).

Monowords include literals, data names, most I/O operations, testing and data conversion on the stack, and user-defined procedures. For example: 1987 - numeric literal, #5 - literal of the number 5, "Scheme List" - text literal, LENGTH - variable name, TOB, NEG, +, &,<, = - имена (обозначения) операций, SORT, CONVERT, ЧИСТКА, СНЯТЬ - имена процедур пользователя.

Prefixes are inherent in commands for describing data and defining procedures, as well as manipulating named data, conditional and repeated execution of procedures, and managing a dictionary. Examples of commands with prefixes:

VAR SUM - create a variable SUM,

: ODD [x] 1 & ; - create an ODD procedure that replaces an odd number with 1, an even number with 0,

0 X - assign the value 0 to the variable X,

BR+ P1 P2 - if the value of its top taken from the stack is positive, then execute P1, otherwise execute P2,

RP CHECK - perform the CHECK procedure again and again,

USE $REAL - open the $REAL subdictionary for use.

Typically, a specific prefix requires a certain number of words after it. So, in the examples just given, the prefixes VAR, !0 and USE each require one word, and the prefix BR+ requires two words. However, the prefix: (colon) allows you to create a command of any length, starting with three words. The end of the command is the word; (semicolon). An arbitrary length is also characteristic of the constant descriptor command CNST A1 ... AJ ; and the procedure multiple selection command BR A1 P1 ... AJ PJ ELSE PN.

Prefixes are special words that, when added to the front of a command, modify its content or define a special execution mode. For example, the VAR X command without a preprefix is ​​an instruction to create a 16-bit variable X. If you attach the BYTE preprefix to it, you get the BYTE VAR X command, which instructs you to create an 8-bit variable (byte) named X. If you use a LONG prefix, then we get LONG VAR X - an instruction to create a 32-bit variable named X.

A preprefix of another type, namely:: (two colons) makes the result of the command resistant to the CLEAR procedure, which removes loose words from the dictionary. Names entered into the dictionary during program construction by the data description and procedure definition commands can be removed from the dictionary after the program has been created and tested, with the exception of a few that are necessary to maintain the finished program. Removal is performed with the CLEAR $ command<имя подсловаря>, which instructs to clear the subdictionary associated with the program, keeping in it only those words whose definitions contain the prefix ::. Examples of commands that generate undeletable words:

:: BYTE CNST LITCODE # #0 #A ;

:: : MOD / [int(a,b),res(a,b)] E2 D [res(a,b)] ;

As the second example, which contains the :: and BYTE prefixes, shows, a command can have more than one prefix.

Thus, a command in a DSSP can be either one word (monoword) or a phrase (phrase), starting with a prefix and containing the number of words set for this prefix, and if the prefix allows an arbitrary number of words, then having a limiting word at the end, or it can be a phrase supplemented at the front with special prefix words.

The basic DSSP language does not contain any more complex syntactic constructions than the command and generally does not contain any constructions other than those discussed above. Even such things as indispensable in programming languages ​​as expression and function are absent in the base language and can be introduced, if necessary, only during its development.

A program in a base language is simply a collection of commands executed in the order in which they appear in the text. Moreover, each command, with the exception of those containing only primitives, during its execution involves a sequence of commands that define the words included in it. The commands involved may in turn contain words denoting command chains, which may also contain words referring to their associated chains, etc. up to the level where the commands contain only primitives.

The general description of the PARA language, which formed the content of this chapter, was devoted to the characteristics of the structure of this language and the basic (initial) set of its commands, which is a set of built-in commands (primitives) of the DSSP processor. Further development of the language and the corresponding increase in processor capabilities is carried out by introducing new procedures, commands, formats and data types constructed using basic tools. As a rule, such development is problem-oriented in nature and is carried out in the form of packages of procedures loaded onto the processor input in addition to the base system.

On the other hand, the basic system can be supplemented with special means implemented on its basis to increase the machine efficiency of DSSP programs. These features include the ability to define individual procedures directly in the command code of the machine being used. The method of defining a procedure does not have any impact on its further use: the names of all procedures are entered into a common dictionary and are completely equal. A number of library programs allow you to use procedures or entire programs written in other languages.

Description of operations and commands

Operations performed on the stack

The operand stack is one of the main elements of the DSSP processor architecture. Most processor instructions use the stack, consuming the operands they need from it and pushing the results onto it. The interpretation of the data on the stack depends on the essence of the problem being solved, i.e., it is ultimately the responsibility of the programmer. Due to the fact that a value pushed onto the stack actually loses its name, it is difficult to determine from the program text which operands a particular operation is applied to and what its results are. Therefore, comments are used to explicitly indicate the operands and results of procedures in the RAYA language. In this case, it is not necessary (and not always possible) to describe the entire contents of the stack. It is absolutely necessary to comment on the upper part of the stack, which is affected by the procedure performed on it, since without this the clarity of the program is lost and its verification becomes difficult.

To achieve program uniformity, these comments should be written taking into account a few simple rules. Like any comment, the description of the data on the stack is enclosed in square brackets. This description is a list of operands that are on the stack at a given point in the program. Each list element characterizes the contents of one stack position; a comma is used as a delimiter. Stack position values ​​are listed from left to right, starting with the deepest element and ending with the top of the stack. The description of an individual operand can be a number, a name, an expression, or any other meaningful entry that explains the meaning of a value located on the stack. Sometimes there are multiple possible values ​​for a stack position. In this case, the values ​​are listed separated by a slash.

Here is an example of a comment reflecting the state of the operand stack:

[start address,N+1,1/0]

At the point in the program where this comment is located, the operand stack must contain at least three positions, with a 1 or 0 at the top, a numeric value equal to N+1 at the sub-top, and some number below it, interpreted as the starting address.

For convenience of indicating the required stack position, we will use the concept of depth. We will assume that the top of the stack lies at depth 1, the sub-top at depth 2, etc. In particular, the value denoted in the example as "start.address." lies at depth 3.

We will begin our study of the basic DSSP language with commands for pushing values ​​onto the stack. The simplest (and most frequently used) command of this type is a numeric literal, that is, an explicit indication of a constant that should be pushed onto the stack. Let, for example, we want to push the numbers 28, -5 and 11 onto the stack. To do this, we need to enter the line from the keyboard:

28 -5 11 and press the key (carriage return). The processor will recognize the entered numbers and push them one by one onto the stack, so that the top will be 11. To verify this, just print the value of the top of the stack on the display screen. To do this, use the DSSP command with the name. (dot). By typing the letter "period" on the keyboard and pressing , we get the answer on the screen: 11, which corresponds to the last value pushed onto the stack. Executing "dot" again produces the same result - this command only renders the vertex without changing the state of the stack.

In order to display the entire contents of the stack on the screen, the DSSP has the command .. (two dots). Having executed it, we get the line on the screen:

As you can see, the form of the printout follows the conventions for commenting stack state (except that a space is used instead of a comma). The .. command does not change the contents of the stack.

A 32-bit word (4 bytes) is used to represent one stack position in the machine's memory; numbers are represented in two's complement. Accordingly, the DSSP processor can correctly perceive only integer numbers lying in the range from -2147483648 to 2147483647. If the entered number cannot be represented by 32 bits (taking into account the sign), then the most significant bits that do not fit are discarded.

In the examples considered, it was assumed that the DSSP processor is in the decimal input/output mode. To set this mode in the PARA language there is a command B10.

In many tasks, it is necessary to interpret the processed data not as numbers, but as binary codes, that is, 32-component bit vectors. DSSP has the ability to work with codes presented in binary, octal or hexadecimal number systems. To set the desired mode, it is enough to execute one of three commands: B2, B8 or B16, after which the processor will accept and print all entered codes in the specified number system.

This feature can be used to convert decimal numbers to number systems with bases 2, 8 and 16. For example, to convert the number 29 you need to enter and execute the following line:

B10 29 B2. B8. B16. As a result, the processor will display a series of numbers on the screen: 00000000035 0000001D which are representations of the decimal number 29 in the three specified number systems. Note that the codes are printed in their machine representation, i.e. with leading zeros and without the signs “+”, “-”. When executing line B10 -2 B8 . will produce the number 37777777776, which is the two's complement octal representation of -2.

When working with hexadecimal codes, collisions may occur between numeric literals and DSSP processor command names. For example, word B8 in hexadecimal I/O mode can be interpreted as an octal mode command and as a hexadecimal constant. To avoid ambiguity, you should start numeric literals with a non-significant zero, for example 0B8.

The basis of the command system of the DSSP processor is the operations of converting data located on the stack. The general rule governing the operation of these operations is that each operation consumes (removes) the operands it requires from the stack and pushes the result values ​​(if any) in their place.

Let's consider processor instructions that implement four arithmetic operations: addition, subtraction, multiplication and division of integers. To depict them in the language of PARADISE the words are used: +, -, * and /, respectively. To get the sum of two numbers on the stack, for example 123 and 45, you need to push these numbers onto the stack and execute the + command. To do this, simply enter the following line from the keyboard (assuming that the decimal input/output mode is set):

123 45 +

If you now display the contents of the stack on the screen (using the .. command), you will see the result of the addition:

The commutative multiplication operation works in a similar way.

When performing non-commutative operations of subtraction and division, the subvertex of the stack is taken as the minuend (divisible), and the top is taken as the subtrahend (divisor). For example, to calculate the difference 151-68 you need to execute the line:

151 68 -

The program for performing an arithmetic operation in the PARA language is characterized by the fact that the operation is located after its corresponding operands. This notation of arithmetic expressions is called postfix (or Polish inverse) notation and is widely used in stack microcalculators. Let, for example, we need to calculate the value of the arithmetic expression ((127+81)*15-(31+117)*21)*3

In postfix notation, this expression will look like this:

127 81 + 15 * 31 117 + 21 * - 3 *

This line (in which the words are separated from each other by spaces) is a ready-made program for calculating our expression by the DSSP processor.

The division / command differs from other arithmetic operations in that its result is two values ​​- the quotient and the remainder. The quotient ends up at the bottom of the stack, and the remainder at the top. A quotient is negative if the dividend and divisor have different signs. The remainder always has the sign of the dividend. Here are some examples of using the division command.

125 7 / [-17,-6] / / /

When performing calculations, error situations may occur: overflow and division by zero. The DSSP processor does not react to them in any way (in particular, when dividing by zero, the contents of the stack do not change), and control over the correct use of operations rests with the programmer.

When programming, you often have to increase or decrease the value of a value by 1 or 2. Special commands have been introduced into the PARA language that perform specified actions on the top of the stack. They are designated by the words: 1+, 1-, 2+, 2-. Executing these commands is equivalent to pushing the required constant (1 or 2) onto the stack and then performing the required arithmetic operation (+ or -). For example, 2+ is equivalent to the word pair 2+. The introduction of these commands into the language was driven by efficiency considerations.

Also, to increase efficiency, the base language of the DSSP processor contains the T0 and T1 commands, which replace the value at the top of the stack with 0 and 1, respectively, regardless of what value was at the top before the specified command. Examples:

The NEG, ABS and SGN commands are also intended for working with numerical data. The NEG command reverses the sign of the top of the stack, ABS replaces the value of the top of the stack with its modulus, SGN consumes a numerical value from the top of the stack and places the sign of the extracted number in its place: -1 - if the number is negative, 1 - if positive, 0 - if equal zero. For example:

5 NEG [-5] ABS SGN

The base language commands MIN and MAX allow you to find the minimum and maximum of two integers. The operands for these instructions are two numbers located at the top and subtop of the stack. The MIN command leaves the minimum number of parameters on the stack, MAX - the maximum of them. For example:

5 0 15 MIN [-5.0] MAX

To find the minimum (maximum) of three numbers on the stack, just use the MIN (MAX) command twice:

MIN MIN [-2]

The SEG command checks whether the number contained at the top of the stack falls into the specified range from a to b (including boundaries) and leaves a sign on the stack as a result: 1 if the number is in the range, and 0 if not:

SEG [sign] for example:

In addition to commands focused on working with numerical data, the command set of the DSSP processor includes a number of operations designed to convert 32-bit codes. These operations treat a stack element as a 32-component bit vector, the components of which are numbered from right to left such that the leftmost bit is numbered 31 and the rightmost bit is numbered 0. The descending numbering of the components follows the numbering of machine word bits adopted for many microprocessors.

The commands performed on bit vectors primarily include bitwise Boolean algebra operations:

    bitwise inversion of the top of the INV stack, changing the value of each bit of the top, i.e., replacing 0 with 1, and 1 with 0;

    bitwise conjunction of the top and subvertex of the stack &, setting the i-th bit of the result, i=31,30,...,0, to the value 1 if the i-th bits of both operands are equal to 1, and in other cases setting the i-th bit equal to 0;

    bitwise disjunction of the top and subvertex of the stack &0, setting the i-th bit of the result, i=31,30,...,0, to the value 0 if the i-th bits of both operands are equal to 0, and in other cases setting the i-th bit equal to 1;

    bitwise addition (non-equivalence) "+" of a vertex and subvertex, setting the i-th bit of the result to 0 if the i-th bits of both operands have the same values, and setting the i-th bit of the result to 1 if the values ​​of the i-th bits of the operands are different.

525 INV 722 & 136 &0 325 "+"

The bitwise conjunction is often used to reset (clear) the bits of a word. To do this, they perform a conjunction of the original word with a mask containing zeros in those bits that need to be cleared and ones in the remaining bits. For example, if you need to reset bits 3 to 5 in some word X, you need to perform its bitwise conjunction with the mask 37777777707. For X=235 we get:

Bitwise disjunction can be used to put the desired combination of bits into a previously cleared group of word bits. Let, for example, you need to put the binary combination 010 into bits 3 through 5 of the word remaining on the stack as a result of the last example. This can be done like this:

Bit manipulation operations also include logical shift commands:

    left shift SHL - each bit of the top of the stack, starting from the 31st, takes the value of the next one in descending order, and the last, zero bit takes the value 0;

    right shift SHR - each bit of the top of the stack, starting from 0, takes the value of the next one in ascending order, and the 31st bit takes the value 0;

    shift at the top SHT - the top element is removed from the stack and treated as an integer N, indicating how many shifts and in what direction should be made at the top of the stack: when N>0 a shift is made to the left, when N<0 - вправо.

B8 125 SHR SHL -2 SHT

Left shift operations can be used to multiply numbers by 2 to the power of N, where N is a natural number that determines the number of shifts. For example, multiplying the number -5 by 8 can be done by shifting the number 3 places to the left:

B10 -5 3 SHT [-40]

The possibility of overflow must be taken into account.

Right shift can be used as a division by 2 to the power of N only for positive numbers, since the most significant (sign) bit is set to zero during right shifts. For example:

whereas

The commands to cyclically shift the top of the stack 1 bit to the right ROR and left ROL are similar to the logical shift commands, except that the pushed outmost bit does not disappear, but is pushed into the vacated space at the opposite end of the 32-bit long word. For example (hexadecimal numbers):

The DSSP processor commands SWB and SWW are also intended for processing binary codes. The SWB function is to swap the bytes of the low-order half of the top of the stack, and the SWW function is to swap the halves of the top of the stack. Let's illustrate how these commands work using hexadecimal I/O mode (in this mode, each byte is represented by two hexadecimal digits):

B16 0ABCD SWB SWB

0ABCDEF12 SWW SWB

Stack manipulation commands play an important role in the PARA language. They do not change the values ​​of the data located on the stack, but only change their location, making it easier to access operands located deep in the stack.

There are three commands for deleting stack elements: D, DD, DS (Drop). The D command removes one (top) element from the stack, DD removes two elements, for example:

D DD D DS removes all elements from the stack (clears the stack):

The command to copy the top of the stack C (Copy) pushes a copy of the current value of its top onto the stack. This is equivalent to duplicating the top element of the stack: the old top becomes the subvertex, and its copy becomes the new top. Example:

Let's show the use of this command using the example of calculating the polynomial p(x)=3*x**2+4*x-5 using Horner's scheme: p(x)=(3*x+4)*x-5. We assume that the value x is contained at the top of the stack.

[x] C 3 * 4 + * 5 -

Along with the command to copy the top of the stack, the PARA language also has commands C2, C3, C4, which copy elements located at depths 2, 3, 4. Their work can be explained with the following examples:

C2 C4

There is also a CT command to copy an element located at a depth specified at the top of the stack. When performing CT, the processor removes the top element from the stack, uses its value as an indicator of the depth of the copied element, and pushes a copy of the latter onto the stack. Thus, copying an element located at depth 5 is specified by a pair of 5 CT instructions, executing which the processor will push the number 5 onto the stack and then execute the CT instruction. Executing CT with parameters 1, 2, 3, 4 is equivalent to commands C, C2, C3, C4, respectively.

Exchange commands E2, E3, E4 (Exchange) rearrange the first (top) element of the stack, respectively, with the 2nd, 3rd, 4th, i.e., with the element located at a depth of 2, 3, 4. For example:

E3 E2

To exchange to a greater depth, use the ET command, which, like CT, uses the value of the top of the stack as an indicator of the depth of the element that is exchanged with the first element. For example:

5 ET

The ET command with parameters 2, 3, 4 is equivalent to the E2, E3, E4 commands.

To illustrate the use of the copy and share commands, consider a learning task. Three numbers are given on the stack. Required to be received on the stack: . You can suggest the following program, the meaning of which is clear from the comments.

C3 C3 C3+

E4+E4

This example shows well how important the role of comments is, reflecting the state of the operand stack.

In programs, it is often necessary to compare numerical values ​​with each other and perform various procedures depending on the results of the comparison. The RAYA language has comparison commands<, =, >. They are defined over numbers and produce the numeric values ​​0 and 1 as a result. So, the command< потребляет из стека два элемента и засылает в стек число 1, если значение нижнего элемента оказалось меньше значения верхнего, а в противном случае засылает 0. Например, в результате выполнения последовательности 5 -20 < в стек будет заслан 0. Команда = засылает 1 в случае равенства потребленных ею элементов. Команда >sends 1 when the bottom element is larger than the top element. To program non-strict comparisons (less than or equal, greater than or equal), the NOT instruction is used, which replaces the value at the top of the stack that is not equal to zero with zero, and equal to zero with one. For example, the evaluation of the logical expression x>=5, where x is some number located at the top of the stack, can be specified as follows:

[x] 5< NOT

Further expansion of the programming capabilities of conditions is provided by the use, along with comparison commands, of the logical operations of conjunction & (logical AND) and disjunction &0 (logical OR). Let, for example, you want to get 1 on the stack if the number x at the vertex belongs to the half-segment C 5< NOT C2 10 <

&E2 2 = &0

Program controls depending on the comparison results will be discussed later.

Defining Procedures

As a basic programming technique, DSSP provides the user with the ability to define named sequences of operations called procedures. Let, for example, you need to calculate the values ​​of the quadratic trinomial 3*x**2-4*x+9 for given values ​​of x. In this case, you should define a procedure that implements the trinomial formula and outputs the result to the terminal, and then apply this procedure to specific values ​​of x. The required procedure, let's call it PX, is defined as follows: PX [x] C 3 * 4 - * 9 + . D ; The colon indicates a "define procedure" operation, with the procedure name followed by a colon after a separating space. The defining sequence of commands (the body of the procedure) is located after the procedure name and ends with a semicolon. In short, the procedure is defined in the form:

: <имя процедуры> <тело процедуры> ;

The RAYA language requires commenting on the state of the operand stack at the beginning and end of a procedure. In the body of the procedure, comments are placed at the discretion of the programmer in places that are difficult to understand.

Comments help humans understand and use the procedure; the processor simply ignores anything enclosed in parentheses. Therefore, when entering the definition of an individual procedure from the terminal, comments can be omitted.

After the procedure definition is entered and the key is pressed the processor is informed about the end of the input, an asterisk appears on the terminal screen, signaling the execution of the “define procedure” command and the processor’s readiness to continue the dialogue. Now you can apply the PX procedure to the x values ​​​​specified from the keyboard, for example, to 2, 3, 4 (produced by the processor is underlined):

* 2 PX 13

*3 PX 24

* 4 PX 41

Let us define a more general procedure for calculating a trinomial of the form a2*x**2+a1*x+a0, which allows you to specify the values ​​of both x and a0, a1, a2. Let's call it PXA:

: PXA C E4 E3 * + * + ;

When using PXA, the values ​​a0, a1, a2, x must be in the required sequence on the stack. For example: a0=1, a1=2, a2=-3, x=4

* 1 2 -3 4 PXA . D -39

The body of a procedure, along with basic processor operations, may contain user-defined procedures. For example, you can define a procedure P that, in addition to the calculations performed by PXA, will print a copy of the result to the terminal and remove the result from the stack.

:PXA. D ;

In particular, the body of a procedure may include the name of the procedure being defined itself, that is, the procedure may be recursive. For example:

: TIME [t] 1- TIME ;

This procedure decreases the value of the top of the stack by 1 and again refers to itself, i.e. it works as a time counter.

The TIME counter, in principle, cannot stop: the procedure of subtracting one will be performed over and over again while the processor is running. But in DSSP there are tools that allow you to control the progress of the process depending on the results obtained - the operation of controlling the progress of the program.

Conditional execution and repetition

A program that is a sequence of commands executed in the order they appear one after another in its notation is called linear. To make the program easily visible (readable) and understandable, it is divided into named parts that have a certain meaning - procedures, each defined by its own sequence of procedures, which in turn are defined by sequences of smaller procedures, etc. to procedures determined directly by sequences of DSSP commands. Such a program, written as a hierarchy of procedure definitions, is called structured. The method of constructing a structured program, which consists in gradually decomposing the problem to be solved into smaller and smaller subtasks, is called structured programming.

Creating not only linear, but also any programs using the structured programming method is possible if there are operations of executing a procedure according to a condition, repeating a procedure, and exiting a repeated procedure. The set of commands of this kind available in the DSSP provides the possibility of structured construction of an arbitrary program.

The conditions for executing or not executing a procedure are formulated relative to the sign of the number, more precisely, relative to the sign of the value that the top of the stack currently has. The main conditional procedure execution command - BRS (BRanch on Sign) instructs to execute one of three procedures named after BRS depending on the sign of the current value of the top of the stack. When executing BRS, the processor removes the top element from the stack, tests its value, and if it is negative, then it performs the first of these procedures, if it is zero, then the second, and if it is positive, then the third. So team

will cause one element to be removed from the stack and procedure N to be executed if the removed value is negative, procedure P to be executed if positive, and procedure Z to be executed if it is zero.

An example of the use of the BRS command is the following SGN procedure definition

: SGN [X] BRS -1 0 1 ;

This procedure replaces the value X at the top of the stack with the number -1 if X<0, числом 0, если X=0, и числом 1, если X>0. The SGN procedure is available in the DSSP as a basic processor operation.

The BRS command, along with selecting one procedure from three data, provides the ability to implement two-valued statements of the form IF-THEN and IF-THEN-ELSE. For example, the sentence if x>0 then P1 else P0 corresponds to the command BRS P0 P0 P1, and the sentence if x<>0 then P - command BRS P NOP P, in which NOP is the name of an empty operation. But in DSSP there is a more efficient implementation of two-valued conditions - the commands IF-, IF0, IF+, BR-, BR0, BR+.

The IF group commands correspond to the IF-THEN statement. For example, the IF- P command instructs to remove the top element from the stack and test its sign, and if this element has a minus sign, then execute procedure P. The IF0 P and IF+ P commands order to execute procedure P, respectively, in the case when the removed element is equal to zero, and in the case when its value is positive.

As an example illustrating the use of IF group commands, we give the definition of a command in the ABS base language that calculates the modulus of the top of the stack.

: ABS [X] C IF-NEG [|X|] ;

The BR-, BR0, and BR+ commands correspond to the IF-THEN-ELSE statement, instructing the selection of one of two procedures named after them. If the sign of an element removed from the stack coincides with that in the command designation, then the procedure named first is executed, and if it does not match, then the second procedure is executed. For example, the command BR0 P0 P1 instructs to execute procedure P0 in the case when the element removed from the stack is equal to zero, and if this condition is not satisfied, then execute procedure P1.

The considered commands allow you to economically program the execution of a procedure depending on these conditions. The most common conditions of the form x<0, x=0, x>0 are directly implemented by the IF group instructions. Conditions x<=0, x<>0, x>=0 are programmed using the instructions BR-, BR0, BR+ by using the empty NOP operation as the first procedure. For example, the if x clause<=0 then P соответствует команда BR+ NOP P. Примером использования команд группы BR может служить следующая реализация команды базового языка NOT, заменяющей нулевое значение вершины стека единицей, а ненулевое - нулем.

: NOT [x] BR0 1 0 ;

Program branching is often done after comparison commands (<, =, >), producing a logical value of 1 or 0 depending on the result of comparing two numbers. The MAX base language command, for example, can be programmed as follows:

: MAX C2 C2< IF+ E2 D ;

The group of branching commands also includes the BR selection command, written in the form:

BR A1 P1 A2 P2 ... AK PK ... AN PN ELSE P0

When implementing this instruction, the processor first executes the pointer procedure A1 and compares the value it pushed onto the stack with the value below it from the previous top of the stack. If the values ​​match, then the top two elements are removed from the stack and the procedure P1 associated with pointer A1 is executed, after which the transition is made to the instruction following the BR instruction (i.e., in the above notation, the one following the word P0 in the program text). If the compared values ​​do not match, then the top one element is removed from the stack (i.e., the result of A1) and the same actions are performed with the pair A2 P2, then, if there is no match, then with the pair A3 P3, etc. up to AN PN inclusive. If none of the attempts yielded a match, the P0 procedure named after the word ELSE is executed. Typically, numeric constants act as pointer procedures, for example:

[x] C BR 5 NEG -3 ABS 0 NOT ELSE T0 [y]

As a result of executing this line, the value y=-5 will be obtained at the top of the stack if x=5; y=3 if x=-3; y=1 if x=0 and y=0 in all other cases.

In general, a pointer procedure can be not only a numeric constant, but also a variable or any other procedure that satisfies the simple requirement that it does not pop anything from the stack and pushes one value onto the stack.

To illustrate how conditional procedure execution operations are used, let's modify the TIME procedure in the previous section so that the counter stops when a given condition occurs:

: TIME [t] 1- C IF+ TIME ;

Now this TIME procedure only calls itself when the top of the stack is positive. The counter will work exactly N times if at the beginning of the first execution of TIME the vertex contains a positive number N. For example, to get 7 operations, you need to set

7 TIME<ВК>

Since IF+ in the TIME definition, like any conditional operation, removes the element under test from the stack, and this element is necessary for subsequent operations, it has to be duplicated by placing the C (Copy) operation before IF+.

Recursion is not the primary means of executing a procedure multiple times. To program cycles in the PARA language there are commands RP (Repeat - repeat) and DO (Do - do, execute).

The RP W command instructs you to perform procedure W over and over again an unlimited number of times. In order for repetitions to stop, the body of procedure W must contain an EX (Exit) operation that is executed under a given condition. The EX operation transitions to the execution of a procedure that follows in the program text the repeated procedure containing this EX operation. Thus, the counter implemented above as the recursive procedure TIME can be programmed to repeat the procedure W, which is defined as follows:

: W [t] 1- C IF0 EX ;

To make the counter work 25 times, you need to execute the line

Along with the EX operation, which is used in conditional execution commands, there are conditional exit operations EX-, EX0, EX+, which produce the same effect as the IF- EX, IF0 EX, IF+ EX commands, i.e., consuming the top element, testing its sign and exiting if the sign matches that specified in the operation designation. The operations EX, EX-, EX0, EX+ can be used not necessarily in the body of the repeating procedure itself (in our case W), but also in the procedures to which it refers.

As an example, consider the problem of finding the greatest common divisor of two natural numbers using the Euclid method. The essence of the method is that you need to subtract a smaller number from a larger number until the numbers become equal to each other. Once equality is achieved, the greatest common divisor will be found.

Programming will be carried out using the top-down development method. First, we define a GCD procedure that captures the general scheme of the algorithm. The parameters of this procedure are two numbers M and N on the stack, for which the greatest common divisor is found. The body of the GCD procedure must specify a cyclic process for converting values ​​on the stack. As a result of this process, two equal numbers should remain on the stack - any of them can be taken as the greatest common divisor. Taking into account these considerations, the GCD procedure can be defined as follows.

: GCD RP STEP [nod(M,N),nod(M,N)] D [nod(M,N)] ;

Now it is necessary to program one step of the iterative process, i.e. define the STEP procedure. The parameters for it are two numbers on the stack. You need to compare these numbers and exit the loop if they are equal, otherwise, subtract the smaller from the larger. This can be done, for example, like this:

: STEP C2 C2 - BRS NOP EX E2 C2 - ;

Now there are no undefined procedures left in the program and you can start checking it. The check should be carried out from the bottom up, i.e. first you need to make sure that the STEP procedure is working correctly and only then - GCD.

A base language DO operation causes the procedure named after it to be repeated N times, where N is the number contained at the top of the stack at the time DO is executed. For example, in order for procedure P to be executed 8 times, you need to set

8 DO P

If there is at least one exit operation in the body of procedure P and its execution condition is satisfied before the specified number of repetitions has occurred, then the repetitions will be terminated by exiting the procedure in the same way as is done in the case of operation RP. For example, when DO repeats the above W procedure whose definition contains IF0 EX, writing [T] 30 DO W will cause 30 repetitions of W if the value of T>=30. If 0

If by the time the DO operation is executed there is a zero or negative value at the top of the stack, then the procedure following the DO will not be executed even once.

To illustrate the use of the DO operation, we define a procedure NUM that counts the number of non-zero bits in the 32-bit word x given at the top of the stack.

We will place the counter for the number of units at the subvertex of the stack. Counting units will consist of repeating the NUMI procedure 32 times, in which we will examine one bit of the word x. Upon exiting the loop, the required number should be at the top of the stack.

: NUM [x] 0 E2 32 DO NUMI D [N] ;

To count non-zero bits, we use the fact that one in the most significant (31st) bit of a word serves as a sign of a negative number. If the word being studied is negative, then one must be added to N. At the end of the NUMI procedure, you need to shift the word under study one bit to the left.

: NUMI C IF- N+ SHL ;

The implementation of the N+ procedure is quite simple: you need to add one to the subtop of the stack without changing the top.

: N+ E2 1+ E2 ;

Repeatable procedures can contain RP and DO operations in their bodies, leading to nested loops, and any depth of nesting is allowed. In this case, there is an EXT operation to exit the nested loop, indicating the depth of nesting at the top of the stack. For example, exiting two nested loops can be specified like this:

It should be borne in mind that using the EXT command requires increased care, since when modifying the program, the nesting depth of loops may change and the corresponding constant before EXT will need to be changed.

Named data

The operand stack is the main, but not the only mechanism for manipulating data in the DSSP. It is also possible, along with procedure definitions, to declare elements and standardly organized collections of elements (so-called structures) of data, which are then available for use by their names. By implementing data declarations, the processor reserves the memory required to store them and provides the necessary mechanisms for accessing this memory.

The basic DSSP language includes a number of directive words discussed below for declaring variables and arrays. In order to expand the system language, other words of this kind and, accordingly, other elements and data structures can be introduced into it.

The word VAR declares a 16-bit numeric variable. For example, record

declares a variable X, that is, it tells the processor that the name X is the name of a variable. The processor associates with this name a 16-bit memory cell in which the value of this variable will be stored. The instruction for assigning the variable X to the value contained at the top of the operand stack has the form

By executing this command, the processor removes the top element from the stack and writes its value to the cell allocated for the variable X.

A command consisting only of a variable name, without the letter ! in front of it, causes the value of this variable to be pushed onto the stack, and the pushing is done by copying the contents of the corresponding memory cell, i.e. the value of the variable remains unchanged. Thus, any occurrence of a variable name X in a program, unless immediately preceded by a word specifying a different action, will push the current value of this variable onto the stack, just as directly given numbers (numeric literals) are pushed onto the stack.

As an example, we give another version of the GCD procedure discussed above in which two working variables are used.

: NOD! X! Y RP STEP X [GCD] ;

: STEP X Y = EX+ X Y BR+ X-Y Y-X ;

: X-Y X Y - ! X ;

: Y-X Y X - ! Y ;

As you can see, the program has become somewhat longer, but its visibility has increased.

The word VCTR declares a one-dimensional array (vector) of 16-bit cells, with the number of the highest element of this array given by the value of the vertex. For example, as a result of recording

9 VCTR ROW, the processor reserves 10 sequentially addressable 16-bit words of memory, forming a ROW(0:9) vector. First, the number 9 is pushed onto the stack, and then the VCTR procedure is executed, using the top element of the stack to determine the length of the ROW vector to be created.

Pushing the value of the j-th element of the ROW vector onto the stack, 0<=j<=9, задается командой

[j]ROW

Using an element number on the stack as a parameter, the ROW vector name causes that number to be replaced by the value of the corresponding element. If the word! is immediately before the name of the ROW vector, then the element of this vector indicated by the vertex is assigned the value of the subvertex, and the depth of the stack is reduced by 2. For example, you can reset the 5th element of the ROW vector like this:

It is also possible to combine constant vectors, i.e. vectors of 16-bit numbers, the values ​​of which are determined when it is declared and do not change subsequently. Thus, a vector of 16-bit constants VC of length L+1 is declared using the word CNST in the form:

CNST VC k0 k1 ... kL ;

where k0, k1, ... kL are commands that push one value onto the stack. Most often these are just numeric literals, but there can also be names of variables, procedures, as well as commands consisting of pairs of words, such as, for example, the command for sending the address of the variable "X" discussed below. Accessing the elements of a constant vector is done in the same way as to components of ordinary vectors. For example:

A multidimensional array of 16-bit words is declared using the word ARR, preceded by the maximum index values ​​for each dimension and the number of dimensions. For example, the three-dimensional array TIR(0:8,0:2,0:24) is declared like this:

The number 3 immediately before ARR indicates the size of the declared array.

Pushing an array element onto the stack is achieved by specifying the index of that element followed by the array name. For example, the command to push the element TIR(0,2,2) onto the stack is expressed as

Accordingly, assigning this element the current value of the top of the stack is specified by the command

All considered examples illustrated the creation of structures from 16-bit words. However, the language also allows you to define 32-bit word and 8-bit byte structures. To do this, the prefix LONG or BYTE is placed before the word defining the structure, respectively. For example,

5 BYTE VCTR X - definition of a 6-component byte vector X;

BYTE CNST Y 65 66 67 ; - definition of a 3-component byte vector constant Y;

10 20 2 LONG ARR MTRX - definition of the matrix of long words MTRX(0:10,0:20).

Reading elements of word and byte structures is performed in the same way as in the case of 16-bit word structures. If the element length is less than 32 bits, the value to be retrieved is placed in the low word or byte of the top of the stack, and the high part of the top is set to zero. The value assigned to an element of a word or byte structure is also the low word or byte of a 32-bit long word on the stack.

Although the 16-bit word format is used when defining data by default, it also has the notation WORD. It is advisable to use this preprefix when the program is intended to be transferred to other machines, where DSSP is also implemented and the default may be different.

Byte data structures are most often used to store and process text information. This is explained by the fact that one byte is allocated in the computer memory to encode one character. To specify character codes in the RAYA language there is a construction #l, where l is any character available on the computer keyboard. The DSSP processor perceives this construction as a command to push the code of the letter l onto the stack. For example:

This construction performs the same actions as a numeric literal equal to the code of the specified letter, but its use is more preferable, since, firstly, it frees you from the need to remember codes and, secondly, it makes programs more understandable. In particular, we can give the following definition of the constant vector Y:

BYTE CNST Y #A #B #C ;

It is often convenient to use a symbolic notation for a numerical constant in a program. To provide this capability, there is a qualifier VALUE:

This command pops the top element from the stack and forms a word with the name immediately following VALUE. The use of this word is equivalent to the use of a numerical constant. For example:

Working with memory by physical addresses

The considered tools provide the ability to name data and manipulate data regardless of the computer's address system. But the base language also includes tools that allow you to manipulate the addresses of memory elements. The address of a variable or array element X is pushed onto the stack with the command

In the case of an array element, this command is preceded by the value of the index(es).

The base language @ command replaces the top-of-stack address of a long memory word with the value that contains that word. For example, the value of variable Y can be pushed onto the stack by executing the following line:

The @B instruction replaces the address with the value of the corresponding byte, setting the high bytes at the top of the stack to zero, and the @L instruction replaces the address with a 32-bit word.

There are also commands for writing values ​​to memory. The!T instruction writes the 16-bit value of the subtop to the address removed from the top of the stack. The!TB command causes a similar write of the low byte of the subvertex to the byte addressed by the vertex, and!TL writes the 32-bit word of the subvertex to the word addressed by the vertex. For example, you can assign the value 15 to the fifth element of the byte vector BV(0:5) with the following commands:

15 5" BV!TB

The need to work with memory at physical addresses usually arises when creating programs that depend on the architecture of a particular computer, for example, when creating I/O drivers.

Additional operations for working with data and memory

In order to achieve greater efficiency and compactness of programs, the following operations have been introduced into the PARA language:

0 <имя переменной>- reset the variable;

1 <имя переменной>- assign a unit to a variable;

1- <имя переменной>- decrease the value of the variable by one;

1+ <имя переменной>- increase the value of the variable by one;

!- <имя переменной>- subtract the value of the top of the stack from the variable;

!+ <имя переменной>- add the value of the top of the stack to the variable.

Each of these operations is easily programmed using variable read and write commands. For example,

0 X is equivalent to 0 ! X

1+ X is equivalent to X 1+ ! X

X is equivalent to X E2 - ! X

Using these operations increases the efficiency and visibility of programs.

In practice, you often want to assign a single value to all elements of an array. For this purpose, there is an operation in the language of PARADISE!!!<имя массива>. Its effect is to assign the value of the top of the stack to all components of the specified array. Operation!!! applicable to arrays with elements of any format.

Usage example:

The space code is written to all components of the BUF byte array.

It is often necessary to obtain information from a program about the data structure behind a name. There are a couple of SIZE commands for this? - display the data element format: 1, 2 or 4 bytes, and DIM? - display the number of data elements in the structure. For example, if the data is declared

3 4 2 LONG ARR Z

then, when applied to them, these commands will give the following result (decimal numbers):

SIZE? X SIZE? Y SIZE? Z

DIM? X DIM? Y DIM? Z

The command set of the DSSP processor includes, as an addition, four commands that allow you to read and write individual bits of computer memory cells. These are the commands @BI, !BI, !BI0, !BI1. The parameters for each of them are the address of the memory word on the stack and the number of the bit in this word (remember that bits are numbered from right to left, starting from zero). The!BI command also assumes that there is a bit value on the stack that needs to be written. The @BI command replaces the specified parameters with the value of the selected bit (0 or 1), the!BI0 and!BI1 commands set the selected bit to 0 and 1, respectively, removing their parameters from the stack, and the!BI command sets the selected bit to the value of the least significant bit of the third element of the stack and removes all three of its parameters from the stack. For example, if the value of variable X is the binary number 101101, then the results of the listed operations will be as follows:

" X [add.X] 3 @BI - third bit of X, 0 " X 3 !BI - X is 100101,

" X [add.X] 0 !BI0 - X is 100100,

" X [add.X] 1 !BI1 - X is equal to 100110.

The PARA language also has tools for working with byte strings located in memory. To specify a byte string, two parameters are pushed onto the stack: the starting address of the string (that is, the address of its first byte) and the length of the string (the number of bytes in it).

The!!!MB command is used to assign all bytes of a string one value (specified on the stack). It consumes three parameters from the stack: , where b is the assigned value, a and l are the starting address and the length of the byte string, respectively. Let, for example, you need to reset elements from the 3rd to 10th byte array TXT(0:20). To do this you can execute the following line:

0 3 "TXT 8!!!MB

as a result, eight consecutive elements of the specified array, starting from the 3rd, will receive the value 0. A similar command!!!MW is intended to fill a sequence of 16-bit words with the same value (the number of words is indicated at the top of the stack), and the command! !!M - to fill a sequence of long words.

The!SB command performs a byte string transfer. Its parameters are: , where a1 and l are the starting address and length of the forwarded string, a2 is the starting address of the string to which the forwarding is performed. As a result of executing the!SB command, a byte string of length l will be located in memory from address a2, which is an exact copy of the string located at address a1 before the transfer was performed. The source string and destination string may overlap. Let, for example, you want to move the elements of the byte array M(0:10) as follows: M(10):=M(9), M(9):=M(8), ..., M(1):= M(0). To do this, you can use the !SB command:

0 " M 10 C2 1+ !SB

As a result, a string of 10 bytes will be moved by one byte towards increasing memory addresses.

The!SB command is convenient for working with stacks of characters (remember that each character is encoded by one byte). It allows, for example, to assign the value of an explicitly specified literal string to a byte array. To specify such a string, use a text literal, i.e. a sequence of characters enclosed in quotation marks, for example "TEXT LITERAL". This construct, when encountered in a program, causes the starting address and length of a byte string containing quoted text to be pushed onto the stack. These parameters can then be used by the!SB command. For example, the fragment "TABLE" 0 " TN !SB will cause the literal "TABLE" to be forwarded to the TN array.

The SRCHB command searches for a specified byte in a string. Parameters: , where b is the byte whose first occurrence must be found, a and n respectively specify the start address and length of the string in which the search is being carried out. If n>0, then the search is carried out from address a to address a+n-1 (in the direction of increasing addresses), if n<0, то поиск ведется с адреса a до адреса a+n+1 (в сторону убывания адресов). В результате выполнения этой команды в стеке оказывается значение d, равное смещению относительно адреса a до первого вхождения байта b. Если такое вхождение не обнаружено, то d=n. Примеры:

#T "TEXT" SRCHB

#A "TEXT" SRCHB

#E "TEXT" [#E,a,4] 1- + -4 [#E,a+3,-4] SRCHB [-2]

Concluding our consideration of tools for working with data, let us dwell on the issue related to storing data in the external memory of a computer, i.e. on magnetic disks. There is a SAVE command in the PARA language<имя файла>, which instructs to save a copy of the system's main memory to disk along with user-defined objects. In this case, the memory areas allocated for data by VAR, VCTR, ARR operations are not output to disk. As a result, when loading a saved system from disk, the values ​​of the specified data are not defined (they must be determined during program execution). In most cases, this is justified, since there is no need to waste disk memory to store working variables, buffers, etc. However, there are data whose values ​​must be determined immediately after booting the system from disk. An example is a variable that stores the speed of data exchange with some external device. When switching to a different exchange rate, it is enough to change the value of this variable without making any corrections to the program.

An indication to the processor that the values ​​of elements of some data structure should be output to disk using the SAVE command is the FIX prefix placed before the structure definition, for example

FIX VAR SPEED 20 FIX BYTE VCTR TABL

Working with data structures defined this way is no different from working with structures defined in the usual way.

Processor Control Commands

The PARA language has a small group of commands designed to control the DSSP processor, or more precisely, the DSSP processor emulator.

The RESTART command causes the processor to restart. In this case, the stack is cleared and a message is displayed

DSSP version XX.XX.XX

Available XXXXXW

and the processor goes into standby mode for command input. This command can be useful when debugging programs. It is also executed when error situations occur: the index goes beyond the array boundaries, free memory is exhausted, etc.

The \G command is used to continue program execution after stopping at an undefined word. If, while executing a procedure, the processor encounters a reference to an undefined word, it issues a message:

stop I don't know<слово> .

where dot is the DSSP processor prompt, signaling that the processor is in a state of halt at an undefined word. In this mode, you can execute any processor commands, just like in normal mode, when the asterisk is the prompt. There are two ways to exit this mode - either by executing the \G command (then the processor will continue executing the interrupted procedure, skipping the undefined word), or by using the RESTART command.

The EXEC command tells the processor to execute a procedure whose address is at the top of the stack. To obtain the address of a procedure, use the command "" (two apostrophes), followed by the name of the procedure. For example, as a result of executing the command

The address of the ABS procedure will be pushed onto the stack. These commands allow you to pass a procedure as a parameter to another procedure.

The group of processor control commands includes the already mentioned SAVE operation<имя файла>, which instructs to save a copy of the system on disk, as well as commands that determine the input source of text information supplied to the input of the processor. Initially, this source is the display keyboard.

LOAD command<имя файла>switches input to the disk file with the specified name. PF command - instructs you to enter commands from the text editor buffer. The TEXEC command passes a text string to the processor input, the parameters of which are specified on the stack. Upon execution of commands contained in the specified sources, input automatically switches to the display keyboard.

Dictionary Control Commands

The input command stream perceived by the processor may, in particular, contain commands for defining procedures and data, causing compilation into an internal representation and storage of the body of the procedure or allocation of memory for the specified data, as well as entering the name of the compiled procedure or data structure into the DSSP dictionary.

The dictionary establishes a correspondence between external (used in the program text) names and the addresses of objects corresponding to these names in the internal representation. When processing a procedure definition or description of a named data, the processor expands the dictionary, forming a new dictionary entry in it containing the name (more precisely, the first 7 characters of the name) and the address of the body of the procedure or data descriptor associated with this name.

When programming top-down, procedure bodies may contain references to not yet defined objects. In this case, dictionary entries (headings) are formed in the dictionary, marked with the sign of uncertainty. To display all undefined names on the display screen, use the UNDEF command.

During the expansion of the dictionary, it is possible to form sub-dictionaries - named collections of dictionary entries. A subdictionary usually combines procedures and data structures related to the same task. To avoid confusion between the names of subdictionaries and other program objects, the name of a subdictionary must begin with the letter $. Access to subdictionaries for their expansion or use can be opened and closed with special commands, which include the following (the name $v means any valid subdictionary).

GROW $v - grow the $v subdictionary, that is, until otherwise instructed, enter the names of all compiled procedures and data into the $v subdictionary;

USE $v - open for use (to search for names in it) the subdictionary $v;

SHUT $v - close the ability to use the subdictionary $v;

ONLY $v - make only the subdictionary $v available for use;

CANCEL - cancel the last ONLY.

There is also a command?$, which prints on the display the names of all subdictionaries and their status - whether the subdictionary is open or closed for searching. The subdictionary whose name is printed at the top is always expanded.

The basic DSSP procedures constitute a sub-dictionary named $PRIME, open for use and extension by default, that is, if there was no command instructing the extension of another sub-dictionary.

Let, for example, use the operation?$ to print the next state of the subdictionaries.

$PRG is open

$PRIME is open

$EDIT is closed

$PRIME is open

SYSTEM is closed

This means that at the moment the subdictionary $PRG is open for growth and use, $PRIME is only for use, and $EDIT and SYSTEM are not available. Note that a subdictionary can consist of several sections with the same names.

There are commands for deleting from the dictionary a particular set of dictionary entries and, perhaps, internal objects associated with them. Thus, the FORGET $v command deletes all names entered into the dictionary (not just the $v subdictionary) since the last execution of the GROW $v command, along with the objects designated by these names, and cancels the growth of the $v subdictionary that it set. The PROGRAM $v command performs the same actions as FORGET $v GROW $v commands executed sequentially. The presence of such a command at the beginning of any program leads to the fact that when the program is recompiled, its old copy will be deleted and a subdictionary will be formed to store objects of the new copy of the program. For example, by performing the FORGET $PRIME operation on the dictionary whose state was shown above, we obtain a new state:

$EDIT is closed

$PRIME is open

SYSTEM is closed

During the execution of the FORGET command, the names of the sections to be deleted are displayed.

Please note that the name of the SYSTEM subdictionary does not begin with the letter $. This is acceptable, but it leads to the fact that applying the FORGET and RPOGRAM commands to this subdictionary does not cause any action (the SYSTEM subdictionary does not seem to exist for them).

Due to the fact that in a ready-made program, for the vast majority of procedures, access by external name is not required, it is possible to remove their names from the dictionary while preserving the internal objects associated with them. The CLEAR $v command removes all names from all sections of the $v subdictionary, with the exception of those that were preceded in the program text (when they were defined) by the prefix:: (two colons). For example, as a result of the processor executing the following program fragment:

:: : X+ Y !+ X ;

CLEAR $EXAM In the $EXAM subdictionary, only the names X and X+ will remain, the dictionary entry Y will be removed (although the variable corresponding to the word Y in the internal representation will remain).

I/O Commands

The main means of user interaction with the DSSP is the terminal, which is usually a cathode-ray display with a keyboard. From the terminal, initial input, editing and debugging of programs, data preparation and all system management are carried out. Programs and data, as well as the DSSP itself, are saved as files on disks and can be printed on a printer. To control input/output, the set of basic DSSP procedures contains the tools described below.

Programming the terminal's operation is provided by commands for input and output of numbers, individual characters and sequences of characters (strings), as well as some additional commands.

The TIB (Terminal Input Byte) command initiates a loop waiting for a key to be pressed on the terminal keyboard. When a key is pressed, the 8-bit code of the corresponding character is pushed onto the stack as the least significant byte of the top, with the highest 3 bytes containing zeros. A copy of the character entered in this way is displayed on the display. There is also a TRB (Terminal Read Byte) command, which differs from TIB in that sending the code of the entered letter to the stack is not accompanied by displaying this letter on the display.

The TIN (Terminal Input Number) command initiates a cycle of entering a number into the stack and displaying a number typed from the keyboard. The number you enter must be a sequence of digits that may begin with a minus sign and end with . Depending on the set input/output mode, numbers are perceived by the processor as hexadecimal, decimal, octal or binary. If a hexadecimal number begins with a digit denoted by a letter, then the digit 0 is added before it. The entered number is converted to binary two's complement code, which is pushed onto the stack as the integer value of a 32-bit long word, i.e. with cutting off bits located to the left of the most significant bit having a weight of 2 to the power of 31.

Each TIN command enters one number. If you need to enter a sequence of numbers in one line, they must be separated by pressing the key , and the TIN command must again be executed to enter each number in the program.

A sequence containing n characters typed from the keyboard is entered into the computer memory in the form of n bytes, located at sequentially increasing addresses, starting with address a, using the TIS (Terminal Input String) command, before which address a and the number of characters n are pushed onto the stack . For example, let a vector of bytes X of sufficient length be declared. You need to enter 9 characters, assigning their values ​​to the elements of this vector, starting with the zero element:

Similarly, using the TOS command, the output of a sequence of n bytes-liters with the starting address a is specified:

Output to the terminal of text elements directly included in the program is ensured by the design

."<текст>"

For example, in order for the text ENTER OPTION NUMBER to appear on the display when executing a certain program fragment, the fragment must contain the entry “ENTER OPTION NUMBER.”

The TON (Terminal Output Number) command displays the number taken from the subtop of the stack, and the length of the output field must be specified at the top. The output number is aligned to the right edge of the field, free positions on the left are filled with spaces, and if the length of the number exceeds the specified field length, then clipping occurs on the left. In decimal I/O mode, negative numbers begin with a minus sign.

The TOB (terminal output byte) command prints the character whose code is specified by the low byte of the top of the stack. The stack depth is reduced by 1.

There are also commands that directly control the display cursor:

CR - go to the beginning of a new line,

SP - space, that is, moving one position to the right.

The BELL command causes a short sound signal ("bell").

Sometimes, when communicating with a terminal, it is necessary to check whether a key has already been pressed and whether the display has already processed the previous output command. This can be done with the TTI (Terminal Test Input) and TTO (Terminal Test Output) commands, which leave a 1 on the stack if the specified event occurs, and 0 otherwise.

Printer output commands are similar to terminal output commands and are based on a similar mnemonic in which the letters LP (Line Printer) have either replaced TO or are added as leading characters. For example, LPCR - transition to the beginning of a new line, LPSP - space, LPN - output of a number from a subvertex in the field specified by the vertex, LPB - output of a character, LPS - output of a string of characters. There is also the [N] LPT command, which moves the print head to position N of the line to be printed, and the LPFF command, which feeds a sheet of paper. To print explicit text, it is convenient to use a text literal and the LPS command, for example:

"FUNCTION VALUES TABLE" LPS

Handling interrupts and exceptions

When programming peripherals, it becomes necessary to handle interrupts. In DSSP this processing is programmed as follows. The program designed to handle the interrupt is a regular DSSP procedure, the definition of which is preceded by the prefix INT, for example INT: A !1+ I ; The INT prefix ensures that the processor state is saved during an interrupt and restored when the interrupt is processed.

To link a processing program to a specific interrupt, use the LINK command:

<адрес вектора>LINK<имя процедуры>when executed, a call to the interrupt handling procedure is recorded along the corresponding vector. The LINK command can perform both static linking of a procedure with an interrupt, which occurs at the time of program compilation, and dynamic linking, during program execution.

A processor interrupt is a way for the system to be notified of an event that has occurred in the outside world. Events that require immediate processing can also occur in the program. They are called exceptional situations. Examples of such situations: division by zero, communication error with the device, end of input file, etc.

In DSSP, exception situations are recorded using command interrupts. A command interrupt is a named operation of calling a response procedure and is declared as follows:

TRAP<имя вызова> <конечная реакция>

For example:

TRAP S1 "Situation S1."

In the first case, the final reaction to interruption S is procedure X, in the second, when interruption S1 occurs, the following message will be displayed on the terminal: Situation S1.

A program whose execution may cause an interrupt can set its own response to it using the intercept command. DSSP provides two types of interceptions: ON and EON. Interception commands can only be used within procedures and have the format:

ON<имя прерывания> <реакция>

EON<имя прерывания> <реакция>For example:

: A ... ON S "Interrupt S" ... ;

: A1 ... EON S1 ABC ... ;

ON and EON set different types of reactions. If a new reaction is specified by the ON command, then when an interrupt occurs, the reaction procedure is executed, after which the interrupted program continues to run. If a reaction is specified by the EON instruction, then first the operand stack takes on the depth that it had at the time the EON instruction was executed, then the reaction is executed, and upon completion, the execution of the procedure in which the EON instruction was used immediately stops.

Let's look at examples. Procedure M enters letters from the terminal keyboard and checks whether it is a number. If the entered character is not a digit, the ND interrupt is raised. TRAP ND "Not a number." : M RP M1 ; : M1 TRB [B] C #0< C2 #9 >&0 IF+ ND [B] TOB ;

The final reaction to an ND interrupt is the message: Not a number.

If M is called from procedure P1, which has its own response to the interrupt ND: P1 ON ND PR1 M ; : PR1 [B] CR "Error." D #0 [#0] ; then when a non-digital character is entered, the ND interrupt will be processed by the PR1 reaction program of type ON, which will cause the message to be issued on a new line: Error. The entered character will be replaced by the character 0, after which M will continue to work.

If M is called from procedure P2: P2 EON ND PR2 M ; : PR2 CR "Error. End of input." ; then when a non-digital character is entered, the ND interrupt will be processed by the PR2 type EON reaction program, which will cause the message to be issued on a new line: Error. End of input., after which P2 will exit. The operand stack will be empty.

If necessary, the interrupt can be raised again in the reaction program, thus extending it to higher-level programs. In this case, either the program specified in the intercept command in the enclosing procedure or the final reaction will handle the interrupt. For example, if you modify PR2 as follows: : PR2 CR "Error. End of input." N.D.; then the message displayed on the terminal will be like this: Error. End of entry. Not a number.

DSSP has several built-in command interrupts, the response to which can be provided in user programs.

Share