Skip to content
s-hadinger edited this page Aug 11, 2021 · 9 revisions

4. Statement

Berry is an imperative programming language. This paradigm assumes that programs are executed step by step. Normally, Berry statements are executed sequentially, and this program structure is called sequential structure. Although the sequence structure is very basic, branch structures and loop structures are usually used in actual programs. Berry provides several control statements to realize this complex flow structure, such as conditional statements and iteration statements.

Except for line comments, carriage returns or line feeds ("\r" and "\n") are only used as blank characters, so statements can be written across lines. In addition, you can write multiple statements on the same line.

You can add a semicolon at the end of the statement to indicate the end of the statement, but the interpreter can usually split the statement automatically without using a semicolon. You can use semicolons to tell the interpreter how to parse the code for the code that will be ambiguous. However, it is better not to write ambiguous code.

4.1 Simple sentence

4.1.1 Expression statement

Expression statements are mainly statements composed of assignment expressions or function call expressions. Other expressions can also form sentences, but they have no meaning. For example, expression 1+2 is a sentence written alone, but it has no effect. The following routines give examples of expression statements and function statements:

a = 1 # Assignment statement
print(a) # Call statement

Line 2 is a simple assignment statement that assigns the literal value i to the variable a. The statement in line 2 is a function call statement, which prints the value of variable a by calling the print function.

Cross-line expressions are written in the same way as single-line expressions, and no special line continuation symbols are required. E.g:

a = 1 +
    func() # Wrap line

You can also write multiple expression statements on one line, and various types of statements can be written on one line. This example puts two expression statements on the same line:

b = 1 c = 2 # Multiple statements

Sometimes the programmer wants to write two statements, but the interpreter may mistakenly think it is one statement. This problem is caused by the ambiguity in the process of grammatical analysis. Take this code as an example:

a = c
(b) = 1 # Be regarded as a function call

Suppose the 4th and 5th lines are intended to be two expression sentences: a = c and (b) = 1, but the interpreter will interpret them as a sentence: a = c(b) = 1. The cause of this problem is that the interpreter incorrectly parses c and (b) into function calls. To avoid ambiguity, we can add a semicolon at the end of the statement to clearly separate the statement:

a = c; (b) = 1;

A better way is not to use parentheses on the left side of the assignment number. Obviously, there is no reason to use parentheses here. Under normal circumstances, complex expressions should not appear on the left side of the assignment operator, but only simple expressions composed of variable names, domain operation expressions, and subscript operation expressions:

a = c b = 1

Using simple expressions only on the left side of the assignment sign will not cause ambiguity in sentence segmentation. Therefore, in most cases, there is no need to use semicolons to separate expressions, and we do not recommend this way of writing.

Block

A Block is a collection of several sentences. A block is a scope, so the variables defined in the block can only be accessed inside the block and its sub-blocks. There are many places where blocks are used, such as if statements, while statements, function declarations, etc. These statements will contain a block through a pair of keywords. For example, the block used in the if statement:

if isOpen
    close()
    print('the device was closed')
end

The statements in lines 2 to 3 constitute a block, which is sandwiched between the pair of keywords if and end (the conditional expression of the statement in if is not in the block). The block does not need to contain any statements, which constitutes an empty block, or it can be said to be a block containing an empty statement. Broadly speaking, any number of consecutive sentences can be called a block, but we prefer to expand the scope of the block as much as possible, which can ensure that the area of the block is consistent with the scope of the scope. In the above example, we tend to think that rows 2 to 3 are a whole block, which is the largest range between if keywords and end keywords.

do Statement

Sometimes we just want to open up a new scope, but don’t want to use any control statements. In this case, we can use the do statement to encapsulate the block. do The statement has no control function. do The sentence has the form

do block end

Among them block is the block we need. This statement uses a pair of do and end keywords to contain blocks. do The statement has no control function, nor does it generate any runtime instructions.

conditional statement

Berry provides if statements to realize the function of conditional control execution. This kind of program structure is generally called branch structure. if The statement will determine the branch of execution based on the true (true) or false (false) conditional expression. In some languages, there are other options for implementing conditional control. For example, languages such as C and C++ provide switch statements, but in order to simplify the design, Berry does not support switch statements.

if Statement

if statement is used to implement the branch structure, which selects the branch of the program according to the true or false of a certain judgment condition. The statement can also include else branch or elif branch. The simple if statement form without branches is

if condition   block   end

condition is a conditional expression. When the value of condition is true, block in the second line will be executed, otherwise the block will be skipped and the statement following end will be executed. In the case of block being executed, after the last statement in the block is executed, it will leave the if statement and start executing the statement following end.

Here is an example to illustrate the usage of the if statement:

if 8 % 2 == 0
    print('this number is even')
end

This code is used to judge whether the number 8 is even, and if it is, it will output this number is even. Although this example is very simple, it is enough to illustrate the basic usage of if sentences.

If you want to have a corresponding branch for execution when the condition is met and not met, use the if statement with the else branch. if else The form of the sentence is

if condition   block
else
block
end

Different from the simple if statement, the if else statement will execute block under the else branch when the value of condition is false. No matter which branch is executed under block, after the last statement in the block is executed, the if else statement will pop out, that is, the statement after end will be executed. In other words, no matter whether the value of condition is true or false, one block will be executed.

Continue to use the judgment of parity as an example, this time change the demand to output corresponding information according to the parity of the input number. The code to achieve this requirement is:

if x % 2 == 0
    print('this number is even')
else
    print('this number is odd')
end

Before running this code, we must first assign an integer value to the variable x, which is the number we want to check for parity. If x is an even number, the program will output this number is even, otherwise it will output this number is odd.Sometimes we need to nest if statements. One way is to nest a if statement under the else branch. This is a very common requirement because many conditions need to be judged consecutively. For this kind of demand, use the if else statement to write:

if expr
    block
else
    if expr
        block
    end
end

Obviously, this way of writing will increase the indentation level of the code, and it is more cumbersome to use multiple end at the end. As an improvement, Berry provides the elif branch to optimize the above writing. Using the elif branch is equivalent to the above code, in the form

if condition
block
elif condition
block
else
block
end

elif The branch must be used after the if branch and before the branch, and the elif branch can be used multiple times in succession. If the condition corresponding to the elif branch is satisfied, the block under the branch will be executed. elif Branching is suitable for situations that require multiple conditions to be judged in sequence.

We use a piece of code that judges positive, negative, and 0 to demonstrate the elif branch:

if x> 0
    print('positive')
elif x == 0
    print('zero')
else
    print('negative')
end

Here too, the variable x must be assigned first. This code is very simple and will not be explained.

Some languages have a problem called dangling "else", which refers to when a if sentence is nested inside another if sentence, where does the else branch belong? Problem with the sentence if. When using C/C++, we must consider the problem of dangling else. In order to avoid ambiguity on the problem of if else, C/C++ programmers often use curly braces to make a branch into a block. In Berry, the branch of the if statement must be a block, which also determines that Berry does not have the problem of overhanging else.

Iteration Statement

Iterative statements are also called loop statements, which are used to repeat certain operations until the termination condition is met. Berry provides while statement and for two iteration statements. Many languages also provide these two statements for iteration. Berry’s while statement is similar to the while statement in C/C++, but Berry’s for statement is only used to traverse the elements in the container, similar to the foreach statement provided by some languages and the one introduced by C++11 New for sentence style. The C-style for statement is not supported.

while Statement

while statement is a basic iterative statement. while statement uses a judgment condition. When the condition is true, the loop body is executed repeatedly, otherwise the loop is ended. The pattern of the statement is

while condition   block   end

When the program runs to the while statement, it will check whether the expression condition is true or false. If it is true, execute the loop body block, otherwise end the loop. After executing the last statement in block, the program will jump to the beginning of the statement while and start the next round of detection. If the condition expression is false when it is first evaluated, the loop body block will not be executed at all (same as the condition expression of the if statement is false).Generally speaking, the value of condition expression should be able to change during the loop, rather than a constant or a variable modified outside the loop, which will cause the loop to not execute or fail to terminate. A loop that never ends is called an endless loop. Usually we usually expect the loop to execute a specified number of times and then terminate. For example, when using the while loop to access all elements in the array, we hope that the number of loop executions is the length of the array, for example:

i = 0
l = ['a','b','c']
while i <l.size()
    print(l[i])
    i = i + 1
end

This loop gets the elements from the array l and prints them. We use a variable i as the loop counter and array index. We let the value of i reach the length of the array l to end the loop. In the last line of the loop body, we add 1 to the value of i to ensure that the next element of the array is accessed in the next loop, and the while loop ends when the number of loops reaches the length of the array.

for Statement

Berry’s for statement is used to traverse the elements in the container, and its form is

for varaibl****e : expressio****n
block   end

expressio****n The value of the expression must be an iterable container or function, such as the range class. for The statement obtains an iterator from the container, and obtains an element in the container every time through the call to the iterator.

varaibl****e is called an iteration variable, which is always defined in the statement for. Therefore varaibl****e must be a variable name and not an expression. The container element obtained from the iterator in each loop will be assigned to the iteration variable. This process occurs before the first statement in block.

The for statement will check whether there are any unvisited elements in the iterator for iteration. If there are, the next iteration will start, otherwise it will end the for statement and execute the statement following end. Currently, Berry only provides read-only iterators, which means that the elements in the container cannot be modified through the iteration variables in the for statement.

The scope of the iteration variable varaibl****e is limited to the loop body block, and the variable will not have any relationship with the variable with the same name outside the scope. To illustrate this point, let’s use an example to illustrate. In this example, we use the for statement to access all the elements in the rang instance and print them out. Of course, we also use this example to demonstrate the scope of loop variables.

i = "Hi, I'm fine." # Outer variable
for i: 0 .. 2
    print(i) # Iteration variable
end
print(i)

In this example, relative to the iteration variable i defined in line 2, the variable i defined in line 1 is an external variable. Running this example will get the following result

0
1
2
Hi, I'm fine

It can be seen that the iteration variable i and the external variable i are two different variables. They just have the same name but different scopes.

for Principle of Statement

Unlike the traditional iterative statement while, the for statement uses iterators to traverse the container. If you need to use the for statement to traverse a custom class, you need to understand its implementation mechanism. When using the for statement, the interpreter hides a lot of implementation details. In fact, for such code:

for i: 0 .. 2
    print(i)
end

Will be translated into the following equivalent code by the interpreter:

var it = __iterator__(0 .. 2)
try
    while true
        var i = it()
        print(i)
    end
except'stop_iteration'
    # do nothing
end

To some extent, the for statement is just a syntactic sugar, it is essentially just a simple way of writing a piece of complex code. In this equivalent code, an intermediate variable it is used. The value of the variable is an iterator. In this example, it is an iterator of the range container 0..2. When processing the for statement, the interpreter hides the intermediate variable of the iterator, so it cannot be accessed in the code.

The parameter of function __iterator__ is a container, and the function returns an iterator of parameters. This function gets the iterator by calling the parameter method. Therefore, if the return value of the iter method is an instance (instance) type, this instance must have a next method and a hasnext method.

The parameter of function __hasnext__ is an iterator, which checks whether the iterator has the next element by calling the hasnext method of the iterator. hasnext The return value of the method is of type boolean. The parameter of function __next__ is also an iterator, which gets the next element in the iterator by calling the next method of the iterator.

So far, the __iterator__, __hasnext__ and __next__ functions simply call some methods of the container or iterator and then return the return value of these methods. Therefore, the equivalent writing of the for statement can also be simplified into this form:

do
    var it = (0 .. 2).iter()
    while (it.hasnext())
        var i = it.next()
        print(i)
    end
end

This code is easier to read. It can be seen from the effective code that the scope of the iterator variable it is the entire for statement, but it is not visible outside the for statement, while the scope of the iteration variable i is in the loop body, so every time Iterations will define new iteration variables.

Jump Statement

The jump statement provided by Berry is used to realize the jump of the program flow in the loop process. Jump statements are divided into break statements and continue statements. These two statements must be used inside iterative statements and can only be used inside functions to jump. Some languages provide goto statements to realize arbitrary jumps within functions, which Berry does not provide, but the effects of goto statements can be replaced by conditional statements and iteration statements.

break Statement

break Used to terminate the iteration statement and jump out. After the execution of the break statement, the nearest level of the iteration statement will be terminated immediately and execution will continue from the position of the first statement after the iteration statement. In order to illustrate the execution flow of the break statement, we use an example to demonstrate:

while true
    print('before break')
    break
    print('after break')
end
print('out of the loop')

In this code, the break statement is in a while loop. Before and after the break statement and after the while statement, we have placed a print statement to test the execution flow of the program. The result of this code is:

before break
out of the loop

This shows that the while statement ends the loop at the break statement position on the 3rd line and the program continues to execute from the 6th line.

continue Statement

continue The statement is also used inside an iteration statement. Its function is to end an iteration and immediately start the next round. Therefore, after the execution of the continue statement, the remaining code in the iteration statement of the nearest layer will no longer be executed, but a new round of iteration will start. Here we use a for statement to demonstrate the function of the continue statement:

for i: 0 .. 5
    if i >= 2
        continue
    end
    print('i =', i)
end
print('out of the loop')

Here, the for statement will iterate 6 times. When the iteration variable i is greater than or equal to 2, the continue statement on line 3 will be executed, and the print statement on line 5 will not be executed thereafter. In other words, line 5 will only be executed in the first two iterations (at this time i<2). The running result of this routine is:

i = 0
i = 1
out of the loop

It can be seen that the value of the variable i is only printed twice, which is in line with expectations. Readers can try to print the value of the variable i before the continue statement. You will find that the for statement does iterate 6 times, indicating that the continue statement does not terminate the iteration.

import Statement

Berry has some predefined modules, such as the math module for mathematical calculations. These modules cannot be used directly, but must be imported with the import statement. There are two ways to import a module:

import nam****e   import nam****e as varaibl****e

nam****e For the name of the module to be imported, when using the first writing method to import the module, the imported module can be called directly by using the module name. The second way of writing is to import a module named nam****e and modify the module name when calling it to varaibl****e. For example, a module named math, we use the first method to import and use:

import math
math.sin(0)

Here directly use math to call the module. If the name of a module is relatively long and it is not convenient to write, you can use the import as statement. Here, assume a module named hardware. We want to call the function setled of the module, we can import the module hardware into the variable named hw and use:

import hardware as hw
hw.setled(true)

Exception Handling

Exception handling The mechanism allows the program to capture and handle exceptions that occur during runtime. Berry supports an exception capture mechanism, which allows the exception capture and handling process to be separated. That is, part of the program is used to detect and collect exceptions, and the other part of the program is used to handle exceptions.

First of all, the problematic program needs to throw an exception first. When these programs are in an exception handling block, a specific program will catch and handle the exception.

Throw an exception

Using the raise statement raises an exception. raise The statement will pass a value to indicate the type of exception so that it can be identified by a specific exception handler. Here is how to use the raise statement:

raise exception
raise exception, message

The value of the expression exception is the thrown Outliers; the optional message expression is usually a string describing the exception information, and this expression is called Abnormal parameter. Berry allows any value to be used as an abnormal value, for example, a string can be used as an abnormal value:

raise'my_error','an example of raise'

After the program executes to the raise statement, it will not continue to execute the statements following it, but will jump to the nearest exception handling block. If the most recent exception handling block is in other functions, the functions along the call chain will exit early. If there is no exception handling block, Abnormal exit will occur, and the interpreter will print the exception error message and the call stack of the error location.When the raise statement is in the try statement block, the exception will be caught by the latter. The caught exception will be handled by the except block associated with the try block. If the thrown exception can be handled by the except block, the execution of this block will continue from the statement after the last except block. If all except statements cannot handle the exception, the exception will be rethrown until it can be handled or the exception exits.

Outliers

In Berry, you can use any value as an outlier, but we usually use short strings. Berry may also throw some exceptions internally. We call these exceptions Standard exception. All standard exception values are of string type. Table 1.1 lists all standard exceptions.

Outliers Description Parameter Description
assert_failed Assertion failed Specific exception information
index_error (usually out of bounds) Specific exception information
io_error IO Malfunction Specific exception information
key_error Key error Specific exception information
runtime_error VM runtime exception Specific exception information
stop_iteration End of iterator no
syntax_error Syntax error
by the compiler
unrealized_error Unrealized function Specific exception information
type_error Type error Specific exception information

Standard exception list

Catch exceptions

Use the excpet statement to catch exceptions. It must be paired with the try statement, that is, a try statement block must be followed by one or more except statement blocks. try-except The basic form of the sentence is

try   block
excpet ...   block   end

The except branch can have the following forms

excpet ..   excpet exception****s
excpet exception****sasvariabl****e
excpet exception****sasvariabl****e, message
excpet .. as variabl****e
excpet .. as variabl****e, message

The most basic except statement does not use parameters, this except branch will catch all exceptions; Catch exception list exception****s is a list of outliers that can be matched by the corresponding except branch, used between multiple values in the list Separate by commas; variabl****e is Abnormal variable, if the branch catches an exception, the outlier will be bound to the variable; message is Abnormal parameter variable, if the branch catches an exception, the abnormal parameter value will be bound To the variable.

When an exception is caught in the try statement block, the interpreter will check the except branch one by one. If the exception value exists in the capture list of a branch, the code block under the branch will be called to handle the exception, and the entire try-except statement will exit after the code block is executed. If all the except branches do not match, the exception will be re-thrown and caught and handled by the outer exception handler.

Clone this wiki locally