A YCP block is a sequence of statements. A block can be evaluated (or call it executed, if you want). For execution of the block, the statements are executed one by one. The following code sample shows a block with some statements. It prints the numbers one to ten to stderr. The result of this block, i.e. what the block is evaluated to is define with the return statement. In this case it is 11.
{ integer n = 1; while (n <= 10) { _debug(n); n = n + 1; } return n; }
YCP knows the following kinds of statements:
Any YCP value is an expression. What the evaluation of an expression means, depends on the data type of the expression. If it is a term structure, it will be evaluated by looking up a function definition and calling that function. For example the builtin function _debug() prints some values to the standard error output. It evaluates always to nil. The following block prints a hello world message:
{ _debug("Hello World!"); }
Note, that evaluation statements always end with a semicolon. The return value of _debug() is ignored in this example. If you want to see it, just use another call to debug:
{ _debug(_debug("Hello World!")); }
Now you will get the following output:
Hello World! nil
Most of the YCP data types can't be evaluated, or in other words, evaluate to themselves. This holds for the types void, boolean, integer, float, string, locale, path and declaration.
{ integer n = 8; _debug(n); _debug(`n); }
You will get the following output:
8 `n
If you prefix a term with a single backquote `, it is not evaluated, only its arguments are evaluated. Thus `foo(7+8) will evaluate to foo(15). You can try the following piece of code to try it out:
{ _debug(`foo(7+8)); }
The evaluation of an expression within YCP can be avoided by quoting it. This makes sense in a context where a YCP expression should be handed over to another component that will evaluate that expression for itself. There are two different kinds of quoting called single quoting (`) and deep quoting (``). In the following example a YCP expression is handed over to SCR with meanings:
--YCP--> There is something left for YCP to evaluate. --SCR--> There is nothing left for YCP to evaluate, hand expression over to SCR after removing all quotes.
The single quote (`) applies only to the expression it is attached to. It does not apply to expressions contained therein. Furthermore it stays in place until YCP evaluation has finished.
integer value = 5; SCR(`term(value)) --YCP--> SCR(`term(5)) --SCR--> term(5)
The deep quote (``) does apply to all expressions contained in the expression it is attached to. The deep quoted expression is evaluated to itself and evaluation of this expression stops thereafter.
integer value = 5; SCR(``term(value)) --SCR--> term(value)
This is the same as:
SCR(`term(`value)) --SCR--> term(value)
Variable declarations in YCP are simliar to C. Before you use a variable, you must declare it. The variable declaration statement looks like this: declaration variablename = initialvalue ;. The initial value is mandatory. The declaration nails down, which values the variable is allowed to hold. You can write a datatype here, like integer, list or boolean or you simple write any, which is considered bad style. More complex declarations are available, but are discussed in another chapter, namely YCP declarations.
If you try to assign a value to a variable that is not allowed by the declaration, you will get a runtime error. Examples of variable declarations:
{ integer num = 42; float num420 = 42.0; string hirn = "This is a string constant"; integer sum = 4 * (num + 8); }
An assignment statement is almost the same as a declaration statement. Just leave out the declaration. It is an error to assign a value to a variable,
{ integer num = 0; num = num + 1; num = 2 * num; hugo = 18; // THIS IS AN ERROR! num = ">:-P"; // THIS IS AN ERROR! string s = ":-)"; // this is ok. }
A conditional statement has the form if ( condition ) thenpart else elsepart. The else elsepart may be omitted. thenpart and elsepart may either be single statements or a list of statements enclosed in curly bracket, i.e a block. The thenpart is executed only in the case, condition evaluates to true, the elsepart otherwise. It is an error, if condition evaluates to something other than true or false.
{ integer a = 10; if (a > 10) _debug("a greater than 10"); else { a = a + 10; _debug("More statements than one require a block"); } }
The while statement executes a block as long as a condition holds. The form is while ( condition ) body. condition must evaluate to true or false. The body may either be one statement or a block of statements.
{ integer a = 0; while (a < 10) a = a + 1; while (a >= 0) { _debug(a); a = a - 1; } }
This statement defines a loop where the condition is checked at the end of the body. Thus the body is executed at least once. The form is do block while ( condition). This example prints the numbers from 0 to 10.
{ integer a = 0; do { _debug(a); a = a + 1; } while (a <= 10); }
This is similar to the do ... while statement, only the condition is logically negated. Here is the upper example converted to repeat ... until.
{ integer a = 0; repeat { _debug(a); a = a + 1; } until (a > 10); }
The break statement is used to immediately leave a loop. The execution is resumed in the first statement after the end of the loop.
{ integer a = 0; repeat { _debug(a); a = a + 1; if (a == 7) break; // Don't like seven. Stop the loop here } until (a>10); // a will never be 10 _debug(a); // This prints 7 }
The continue statement is used to immediately begin the next turn of a loop. For a while loop, it jumps to the beginning of the loop and checks the condition. For a do ... while or repeat ... until loop, it goes to the end of the loop end checks the condition.
{ integer a = 0; while (a < 10) { a = a + 1; if (a % 2 == 1) continue; _debug("This is an even number:" + a); } }
With the return statement you do two things:
The following block evaluates to 42;
{ return 42; _debug("This command will never be executed"); }
If blocks are nested, i.e. if a block is contained in another block in form of a statement, the return statement leaves all nested blocks and defines the value of the outermost block. If a block is used in an expression other than a block, and that expression is contained in an outer block, the return statement of the inner block won't leave the outer block but define the value of the inner one. Examples: This program evaluates to 18:
{ while (true) { return 18; } }This program evaluates to 3:
{ integer a = 1 + { return 2; }; return a; }