    TrafficLightControl ::=
        #ignore(C++) // ignore C++-like comments and whitespaces
        #continue // a syntax error will occur if the BNF sequence fails
        [strategy]* // repetition of strategies consuming
        #empty // end of file necessarily reached after the reading of strategies
        ;

    strategy ::=
        #readIdentifier:"strategy" // identifier must be worth 'strategy'
        #continue // the rest of the BNF sequence doesn't have to fail
        #readIdentifier:sName // assign the consumed id to a local variable
        // the '=>' symbol escapes the BNF to execute a non-BNF instruction
        => if this.strategies.findElement(sName) {
            // Error! The strategy already exists in the parse tree!
            error("cannot define the strategy '" + sName + "' twice!");
        }
        // insert the strategy to the parse tree and keep a reference
        => insert this.strategies[sName].name = sName;
        => localref theStrategy = this.strategies[sName];
        '{'
        start_condition(theStrategy) // when to trigger the strategy
        [rule(theStrategy)]+ // at least one rule to parse
        '}'
        ;

    start_condition(theStrategy : node) ::=
        #continue
        #readIdentifier:"start"     // add to the parse tree the condition
        condition:theStrategy.start // to start running the strategy
        ';'
        ;

    rule(theStrategy : node) ::=
        condition:sAntecedent // the antecedent of the rule is a condition
        #continue
        "=>"
        => pushItem theStrategy.rules; // add a new rule in the list
        // access to the last element of the list for inserting a new attribute
        => insert theStrategy.rules#back.condition = sAntecedent;
        => pushItem theStrategy.rules#back.actions; // add a new action
        #readIdentifier:sAction // keyword of the action to execute
        // call of a generic BNF non-terminal, resolved by 'sAction'
        rule_action<sAction>(theStrategy.rules#back.actions#back)
        [
            ',' #continue // a comma separates the actions
            => pushItem theStrategy.rules#back.actions;
            #readIdentifier:sAction
            rule_action<sAction>(theStrategy.rules#back.actions#back)
        ]*
        ';'
        ;

    // A generic BNF non-terminal instantiated on "duration" constant
    rule_action<"duration">(theAction : node) ::=
        #continue
        => theAction = "duration"; // type of action
        '('
        street_segment(theAction.crossroad_entry) // entry point
        ','
        time_sequence(theAction.durations) // traffic light durations
        ')'
        ;

    rule_action<"activate">(theAction : node) ::=
        #continue
        => theAction = "activate";
        '(' #readIdentifier:theAction.strategy ')'
        ;

    rule_action<"desactivate">(theAction : node) ::=
        => theAction = "desactivate";
        ;

    street_segment(theSegment : node) ::=
            #readIdentifier:theSegment.crossroad
            #continue "->"
            => insert theSegment.direction = "c->s";
            #readCString:theSegment.street
        |
            #readCString:theSegment.street
            #continue "->"
            => insert theSegment.direction = "s->c";
            #readIdentifier:theSegment.crossroad
        ;

    time_sequence(theSequence : node) ::=
        #continue
        => pushItem theSequence;
        timeInSeconds:theSequence#back
        [
            '/' #continue
            => pushItem theSequence;
            timeInSeconds:theSequence#back
        ]+
        ;

    // This BNF non-terminal reads a time like 1min15 and
    // restitutes it in seconds: the keyword 'value' means that
    // the non-terminal will return its own transformation rather
    // than the consumed character sequence.
    timeInSeconds:value ::=
        #readInteger:iMin
        #continue
        "min"
        // arithmetic expressions are enclosed between '$' symbols
        => timeInSeconds = $iMin * 60$;
        #readInteger:iSec
        => timeInSeconds = $timeInSeconds + iSec$;
        ;

    condition ::=
        !'}' // look ahead one character if no trailing brace
        [
                #readCString // bypass string: may contain ';' or '=>'
            |
                #readCChar // same reason
            |
                ~[';' | "=>"] // consume if neither ';' nor '=>' reached
        ]*
        ;

Generated by CodeWorker v3.11.0.1 from CWscript2HTML.cwp.