next up previous contents index
Next: Global and Local Variables Up: Statements and Expressions Previous: Statements   Contents   Index

Expressions

Expressions in Bro are very similar to those in C, with similar precedence:

[parenthesized] Syntax:
( expr )
Parentheses are used as usual to override precedence.

[constant] Any constant value (§ ) is an expression.

[variable] The name of a variablevariables is an expression.

[increment, decrement] Syntax:

++ expr
- expr
Increments or decrements the given expression, which must correspond to an assignable value (variable, table element, or record element) and of a number type.

Yields the value of the expression after the increment.

Unlike with C, these operators only are defined for ``pre''-increment/decrement; there is no post-increment/decrement.

[negation] Syntax:

! expr
- expr
Yields the boolean §  or arithmetic negation for values of boolean or numeric (or interval) types, respectively.

[positivation] Syntax:

+ expr
Yields the value of expr, which must be of type numeric or interval.

The point of this operator is to explicitly convert a value of type count to int. For example, suppose you want to declare a local variable code to be of type int, but initialized to the value 2. If you used:

    local code = 2;
then Bro's implicit typing would make it of type count, because that's the type of a constant specified by a string of digits. You could instead use:
    local code = +2;
to direct the type inferencing to instead assign a type of int to code. Or, of course, you could specify the type explicitly:
    local code:int = 2;

[arithmetic] Syntax:

expr$_{1}$ + expr$_{2}$
expr$_{1}$ - expr$_{2}$
expr$_{1}$ * expr$_{2}$
expr$_{1}$ / expr$_{2}$
expr$_{1}$ % expr$_{2}$
The usual C arithmetic operators, defined for numeric types, except modulus (%) is only defined for integral types.

[logical] Syntax:

expr$_{1}$ && expr$_{2}$
expr$_{1}$ || expr$_{2}$
The usual C logical operators, defined for boolean types.

[equality] Syntax:

expr$_{1}$ == expr$_{2}$
expr$_{1}$ "!= expr$_{2}$
Compares two values for equality or inequality, yielding a bool value. Defined for all non-compound types except pattern.

[relational] Syntax:

expr$_{1}$ < expr$_{2}$
expr$_{1}$ <= expr$_{2}$
expr$_{1}$ > expr$_{2}$
expr$_{1}$ >= expr$_{2}$
Compares two values for magnitude ordering, yielding a bool value. Defined for values of type numeric, time, interval, port, or addr.

Note: TCP port values are considered less than UDP port values.

Note: IPv4 addr values less than IPv6 addr values.

Deficiency: Should also be defined at for string values.

[conditional] Syntax:

expr$_{1}$ ? expr$_{2}$ : expr$_{3}$
Evaluates expr$_{1}$ and, if true, evaluates and yields expr$_{2}$, otherwise evaluates and yields expr$_{3}$. expr$_{2}$ and expr$_{3}$ must have compatible types.

[assignment] Syntax:

expr$_{1}$ = expr$_{2}$
Assigns the value of expr$_{2}$ to the storage defined by expr$_{1}$, which must be an assignable value (variable, table element, or record element). Yields the assigned value.

[function call] Syntax:

expr$_{1}$ ( expr-list$_{2}$ )
Evaluates expr$_{1}$ to obtain a value of type function, which is then invoked with its arguments bound left-to-right to the values obtained from the comma-separated list of expressions expr-list$_{2}$. Each element of expr-list$_{2}$ must be assignment-compatible with the corresponding formal argument in the type of expr$_{1}$. The list may (and must) be empty if the function does not take any parameters.

[anonymous function] Syntax:

function ( parameters ) body
Defines an anonymous function, which, in abstract terms, is how you specify a constant of type function. parameters has the syntax of parameter declarations for regular function definitions, as does body, which is just a list of statements enclosed in braces.

Anonymous functions can be used anywhere you'd usually instead use a function declared in the usual direct fashion. For example, consider the function:

    function demo(msg: string): bool
        {
        if ( msg == "do the demo" )
            {
            print "got it";  
            return T;
            }
        else
            return F;
        }
You could instead declare demo as a global variable of type function:
global demo: function(msg: string): bool;
and then later assign to it an anonymous function:
    demo = function (msg: string): bool
        {
        if ( msg == "do the demo" )
            {
            print "got it";
            return T;
            }
        else
            return F;
        };
You can even call the anonymous function directly:
    (function (msg: string): bool
        {
        if ( msg == "do the demo" )
            {
            print "got it";
            return T;
            }
        else
            return F;
        })("do the demo")
though to do so you need to enclose the function in parentheses to avoid confusing Bro's parser.

One particularly handy form of anonymous function is that used for &default.

[event scheduling] Syntax:

schedule expr$_{1}$ { expr$_{2}$ ( expr-list$_{3}$ ) }
Evaluates expr$_{1}$ to obtain a value of type interval, and schedules the event given by expr$_{2}$ with parameters expr-list$_{3}$ for that time. Note that the expressions are all evaluated and bound at the time of execution of the schedule expression; evaluation is not deferred until the future execution of the event handler.

For example, we could define the following event handler:

    event once_in_a_blue_moon(moon_phase: interval)
        {
        print fmt("wow, a blue moon - phase %s", moon_phase);
        }
and then we could schedule delivery of the event for 6 hours from the present, with a moon_phase of 12 days, using:
    schedule +6 hr { once_in_a_blue_moon(12 days) };
Note: The syntax is admittedly a bit clunky. In particular, it's easy to (i) forget to include the braces (which are needed to avoid confusing Bro's parser), (ii) forget the final semi-colon if the schedule expression is being used as an expression-statement, or (iii) erroneously place a semi-colon after the event specification but before the closing brace.

Timer invocation is inexact. In general, Bro uses arriving packets to serve as its clock (when reading a trace file off-line, this is still the case--the timestamp of the latest packet read from the trace is used as the notion of ``now''). Once this clock reaches or passes the time associated with a queued event, Bro will invoke the event handler, which is termed ``expiring'' the timer. (However, Bro will only invoke max_timer_expires timers per packet, and these include its own internal timers for managing connection state, so this can also delay invocation.)

It will also expire all pending timers (whose time has not yet arrived) when Bro terminates; if you don't want those event handlers to activate in this instance, you need to test done_with_network.

You would think that schedule should just be a statement like event invocation is, rather than an expression. But it actually does return a value, of the undocumented type timer. In the future, Bro may provide mechanisms for manipulating such timers; for example, to cancel them if you no longer want them to expire.

[index] Syntax:

expr$_{1}$ [ expr-list$_{2}$ ]
Returns the sub-value of expr$_{1}$ indexed by the value of expr-list$_{2}$, which must be compatible with the index type of expr$_{1}$.

expr-list$_{2}$ is a comma-separated list of expressions (with at least one expression listed) whose values are matched left-to-right against the index types of expr$_{1}$.

The only type of value that can be indexed in this fashion is a table. Note: set's cannot be indexed because they do not yield any value. Use in to test for set membership.

[membership] Syntax:

expr$_{1}$ in expr$_{2}$
expr$_{1}$ !in expr$_{2}$
Yields true (false, respectively) if the index expr$_{1}$ is present in the table or set expr$_{2}$.

For example, if alert_level is a table index by an address and yielding a count:

    global alert_level: table[addr] of count;
then we could test whether the address 127.0.0.1 is present using:
    127.0.0.1 in alert_level

For table's and set's indexed by multiple dimensions, you enclose expr$_{1}$ in brackets. For example, if we have:

    global connection_seen: set[addr, addr];
then we could test for the presence of the element indexed by 8.1.14.2 and 129.186.0.77 using:
    [8.1.14.2, 129.186.0.77] in connection_seen

We can also instead use a corresponding record type. If we had

    local t = [$x = 8.1.14.2, $y = 129.186.0.77]
then we could test:
    t in connection_seen

[pattern matching] Syntax:

expr$_{1}$ == expr$_{2}$
expr$_{1}$ "!= expr$_{2}$
expr$_{1}$ in expr$_{2}$
expr$_{1}$ "!in expr$_{2}$
As discussed for pattern values, the first two forms yield true (false) if the pattern expr$_{1}$ exactly matches the string expr$_{2}$. (You can also list the string value on the left-hand side of the operator and the pattern on the right.)

The second two forms yield true (false) if the pattern expr$_{1}$ is present within the string expr$_{2}$. (For these, you must list the pattern as the left-hand operand.)

[record field access] Syntax:

expr $ field-name
Returns the given field field-name of the record expr. If the record does not contain the given field, a compile-time error results.

[record constructor] Syntax:

[ field-constructor-list ]
Constructs a record value. The field-constructor-list is a comma-separated list of individual field constructors, which have the syntax:
$ field-name = expr

For example,

    [$foo = 3, $bar = 23/tcp]
yields a record with two fields, foo of type count and bar of type port. The values used in the constructor needn't be constants, however; they can be any expression of an assignable type.

[record field test] Syntax:

expr ?$ field-name
Returns true if the given field has been set in the record yielded by expr. Note that field-name must correspond to one of the fields in the record type of expr (otherwise, the expression would always be false). The point of this operator is to test whether an &optional field of a record has been assigned to.

For example, suppose we have:

    type rap_sheet: record {
        num_scans: count &optional;
        first_activity: time;
    };
    global the_goods: table[addr] of rap_sheet;
and we want to test whether the address held in the variable perp exists in the_goods and, if so, whether num_scans has been assigned to, then we could use:
    perp in the_goods && the_goods[perp]?$num_scans


next up previous contents index
Next: Global and Local Variables Up: Statements and Expressions Previous: Statements   Contents   Index
Vern Paxson 2002-11-17