diff --git a/scripts/base/protocols/ftp/main.zeek b/scripts/base/protocols/ftp/main.zeek index afe44397c2..877fd9192c 100644 --- a/scripts/base/protocols/ftp/main.zeek +++ b/scripts/base/protocols/ftp/main.zeek @@ -216,7 +216,7 @@ function ftp_message(c: connection) delete s$data_channel; } -const have_cluster = Cluster::is_enabled(); +const cluster_is_enabled = Cluster::is_enabled(); const should_publish = Cluster::local_node_type() == Cluster::PROXY || Cluster::local_node_type() == Cluster::MANAGER; @@ -250,7 +250,7 @@ function add_expected_data_channel(s: Info, chan: ExpectedDataChannel) Analyzer::schedule_analyzer(chan$orig_h, chan$resp_h, chan$resp_p, Analyzer::ANALYZER_FTP_DATA, 5mins); - if ( have_cluster ) + if ( cluster_is_enabled ) Broker::publish(ftp_relay_topic(), sync_add_expected_data, minimize_info(s), chan); } @@ -466,7 +466,7 @@ hook finalize_ftp_data(c: connection) if ( [c$id$resp_h, c$id$resp_p] in ftp_data_expected ) { delete ftp_data_expected[c$id$resp_h, c$id$resp_p]; - if ( have_cluster ) + if ( cluster_is_enabled ) Broker::publish(ftp_relay_topic(), sync_remove_expected_data, c$id$resp_h, c$id$resp_p); } } diff --git a/scripts/base/protocols/irc/dcc-send.zeek b/scripts/base/protocols/irc/dcc-send.zeek index 323bdd75d8..64669b07df 100644 --- a/scripts/base/protocols/irc/dcc-send.zeek +++ b/scripts/base/protocols/irc/dcc-send.zeek @@ -44,7 +44,7 @@ function dcc_relay_topic(): string &is_used return rval; } -const have_cluster = Cluster::is_enabled(); +const cluster_is_enabled = Cluster::is_enabled(); const should_publish = Cluster::local_node_type() == Cluster::PROXY || Cluster::local_node_type() == Cluster::MANAGER; @@ -92,7 +92,7 @@ function log_dcc(f: fa_file) delete dcc_expected_transfers[cid$resp_h, cid$resp_p]; - if ( have_cluster ) + if ( cluster_is_enabled ) Broker::publish(dcc_relay_topic(), dcc_transfer_remove, cid$resp_h, cid$resp_p); return; @@ -119,7 +119,7 @@ event irc_dcc_message(c: connection, is_orig: bool, Analyzer::schedule_analyzer(0.0.0.0, address, p, Analyzer::ANALYZER_IRC_DATA, 5 min); dcc_expected_transfers[address, p] = c$irc; - if ( have_cluster ) + if ( cluster_is_enabled ) Broker::publish(dcc_relay_topic(), dcc_transfer_add, address, p, c$irc); } @@ -139,7 +139,7 @@ hook finalize_irc_data(c: connection) { delete dcc_expected_transfers[c$id$resp_h, c$id$resp_p]; - if ( have_cluster ) + if ( cluster_is_enabled ) Broker::publish(dcc_relay_topic(), dcc_transfer_remove, c$id$resp_h, c$id$resp_p); } diff --git a/scripts/policy/frameworks/netcontrol/catch-and-release.zeek b/scripts/policy/frameworks/netcontrol/catch-and-release.zeek index 839bb8f7db..b069706323 100644 --- a/scripts/policy/frameworks/netcontrol/catch-and-release.zeek +++ b/scripts/policy/frameworks/netcontrol/catch-and-release.zeek @@ -198,11 +198,11 @@ function populate_log_record(ip: addr, bi: BlockInfo, action: CatchReleaseAction return log; } -const have_cluster = Cluster::is_enabled(); -const is_mgr = have_cluster && Cluster::local_node_type() == Cluster::MANAGER; -const is_not_mgr = have_cluster && Cluster::local_node_type() != Cluster::MANAGER; +const cluster_is_enabled = Cluster::is_enabled(); +const is_mgr = cluster_is_enabled && Cluster::local_node_type() == Cluster::MANAGER; +const is_not_mgr = cluster_is_enabled && Cluster::local_node_type() != Cluster::MANAGER; -const single_enforcement_point = ! have_cluster || is_mgr; +const single_enforcement_point = ! cluster_is_enabled || is_mgr; function per_block_interval(t: table[addr] of BlockInfo, idx: addr): interval { @@ -229,7 +229,7 @@ global blocks: table[addr] of BlockInfo = {} &expire_func=per_block_interval; -@if ( have_cluster ) &analyze +@if ( cluster_is_enabled ) &analyze @if ( is_mgr ) &analyze event zeek_init() diff --git a/scripts/policy/protocols/ssl/validate-certs.zeek b/scripts/policy/protocols/ssl/validate-certs.zeek index 777f2a4551..42d30ae6f9 100644 --- a/scripts/policy/protocols/ssl/validate-certs.zeek +++ b/scripts/policy/protocols/ssl/validate-certs.zeek @@ -61,9 +61,9 @@ export { global intermediate_cache: table[string] of vector of opaque of x509; -const have_cluster = Cluster::is_enabled(); +const cluster_is_enabled = Cluster::is_enabled(); -@if ( have_cluster ) &analyze +@if ( cluster_is_enabled ) &analyze event zeek_init() { Broker::auto_publish(Cluster::worker_topic, SSL::intermediate_add); @@ -74,18 +74,18 @@ event zeek_init() function add_to_cache(key: string, value: vector of opaque of x509) { intermediate_cache[key] = value; - if ( have_cluster ) + if ( cluster_is_enabled ) event SSL::new_intermediate(key, value); } -@if ( have_cluster && Cluster::local_node_type() != Cluster::MANAGER ) &analyze +@if ( cluster_is_enabled && Cluster::local_node_type() != Cluster::MANAGER ) &analyze event SSL::intermediate_add(key: string, value: vector of opaque of x509) { intermediate_cache[key] = value; } @endif -@if ( have_cluster && Cluster::local_node_type() == Cluster::MANAGER ) &analyze +@if ( cluster_is_enabled && Cluster::local_node_type() == Cluster::MANAGER ) &analyze event SSL::new_intermediate(key: string, value: vector of opaque of x509) { if ( key in intermediate_cache ) diff --git a/src/ActivationManager.h b/src/ActivationManager.h index 09d6afd282..24d528e931 100644 --- a/src/ActivationManager.h +++ b/src/ActivationManager.h @@ -16,7 +16,7 @@ using AttrVec = std::unique_ptr>; class ActivationManager; /** - * Expresses an event (with one of the above types) occurring during an + * Expresses an event (of one of the AE_Type types below) occurring during an * @if &analyze. Events reflect what *could* have happened rather than * what *did* happen, so events will be present even for @if &analyze blocks * that were skipped due to their condition evaluating to false. @@ -111,7 +111,7 @@ public: CurrSubEvents().push_back(std::move(ae)); } - // Changes this events accrural of subevents to correspond to its + // Changes this event's accrual of subevents to correspond to its // "else" branch rather than its main/true branch. void SwitchToElse() { @@ -159,7 +159,7 @@ public: Activation(ExprPtr cond, bool _is_activated, bool _parent_activated, int _cond_depth); ~Activation(); - // True if we're in the part of the @activiate-if conditional for + // True if we're in the part of the @if &analyze conditional for // which we should be incorporating statements (making changes to // globals, adding function bodies, etc.). bool IsActivated() const { return is_activated; } @@ -257,7 +257,7 @@ public: // integer to match similar other structures in the scanner. int ActivationDepth() const { return static_cast(activation_stack.size()); } - // Tells the manager to being a new @if &analyze conditional. + // Tells the manager to begin a new @if &analyze conditional. // "cond" is the associated condition, "activate" reflects whether // the condition is true, and "cond_depth" is the depth of any // parent @if constructs. diff --git a/src/parse.y b/src/parse.y index e61360d468..9bc7664141 100644 --- a/src/parse.y +++ b/src/parse.y @@ -5,10 +5,10 @@ // Switching parser table type fixes ambiguity problems. %define lr.type ielr -%expect 212 +%expect 211 %token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY -%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATACTIVATEIF TOK_ATIFDEF TOK_ATIFNDEF +%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF %token TOK_BOOL TOK_BREAK TOK_CASE TOK_OPTION TOK_CONST %token TOK_CONSTANT TOK_COPY TOK_COUNT TOK_DEFAULT TOK_DELETE %token TOK_DOUBLE TOK_ELSE TOK_ENUM TOK_EVENT TOK_EXPORT TOK_FALLTHROUGH @@ -1517,12 +1517,6 @@ conditional: reporter->Error("@if &analyze cannot appear inside a function body"); do_atif($3, true); } - | TOK_ATACTIVATEIF '(' expr ')' - { - if ( in_body ) - reporter->Error("@if &analyze cannot appear inside a function body"); - do_atif($3, true); - } | TOK_ATIFDEF '(' TOK_ID ')' { do_atifdef($3); } | TOK_ATIFNDEF '(' TOK_ID ')' diff --git a/src/zeek-setup.cc b/src/zeek-setup.cc index 5cc5963d64..53413818a6 100644 --- a/src/zeek-setup.cc +++ b/src/zeek-setup.cc @@ -184,7 +184,7 @@ zeek::plugin::Manager* zeek::plugin_mgr = nullptr; zeek::detail::RuleMatcher* zeek::detail::rule_matcher = nullptr; zeek::detail::DNS_Mgr* zeek::detail::dns_mgr = nullptr; zeek::detail::TimerMgr* zeek::detail::timer_mgr = nullptr; -zeek::detail::ActivationManager* zeek::detail::activation_mgr; +zeek::detail::ActivationManager* zeek::detail::activation_mgr = nullptr; zeek::logging::Manager* zeek::log_mgr = nullptr; zeek::threading::Manager* zeek::thread_mgr = nullptr; diff --git a/testing/btest/Baseline/language.at-if-analyze-invalid-10/out b/testing/btest/Baseline/language.at-if-analyze-invalid-10/out index bb31a3c8ca..e0145a612a 100644 --- a/testing/btest/Baseline/language.at-if-analyze-invalid-10/out +++ b/testing/btest/Baseline/language.at-if-analyze-invalid-10/out @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -warning in <...>/at-if-analyze-invalid.zeek, line 5: @if &analyze inside conditional -error in <...>/at-if-analyze-invalid.zeek, line 6: unknown identifier warning_and_noticed_syntax_err_F, at or near "warning_and_noticed_syntax_err_F" +warning in <...>/at-if-analyze-invalid.zeek, line 6: @if &analyze inside conditional +error in <...>/at-if-analyze-invalid.zeek, line 7: unknown identifier warning_and_noticed_syntax_err_F, at or near "warning_and_noticed_syntax_err_F" diff --git a/testing/btest/Baseline/language.at-if-analyze-invalid-2/out b/testing/btest/Baseline/language.at-if-analyze-invalid-2/out index 6189726131..0d3e9e1ffb 100644 --- a/testing/btest/Baseline/language.at-if-analyze-invalid-2/out +++ b/testing/btest/Baseline/language.at-if-analyze-invalid-2/out @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. error in <...>/at-if-analyze-invalid.zeek, line 4: @if &analyze cannot appear inside a function body -error in <...>/at-if-analyze-invalid.zeek, line 5: unknown identifier warning_and_noticed_syntax_error_F, at or near "warning_and_noticed_syntax_error_F" +error in <...>/at-if-analyze-invalid.zeek, line 6: unknown identifier warning_and_noticed_syntax_error_F, at or near "warning_and_noticed_syntax_error_F" diff --git a/testing/btest/Baseline/language.at-if-analyze-invalid-3/out b/testing/btest/Baseline/language.at-if-analyze-invalid-3/out index 585b8b2e32..9a49cf8a6a 100644 --- a/testing/btest/Baseline/language.at-if-analyze-invalid-3/out +++ b/testing/btest/Baseline/language.at-if-analyze-invalid-3/out @@ -1,2 +1,2 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -error in <...>/at-if-analyze-invalid.zeek, line 3: unknown identifier noticed_syntax_error_T, at or near "noticed_syntax_error_T" +error in <...>/at-if-analyze-invalid.zeek, line 4: unknown identifier noticed_syntax_error_T, at or near "noticed_syntax_error_T" diff --git a/testing/btest/Baseline/language.at-if-analyze-invalid-4/out b/testing/btest/Baseline/language.at-if-analyze-invalid-4/out index e3b6d0640d..df3c42aa07 100644 --- a/testing/btest/Baseline/language.at-if-analyze-invalid-4/out +++ b/testing/btest/Baseline/language.at-if-analyze-invalid-4/out @@ -1,2 +1,2 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -error in <...>/at-if-analyze-invalid.zeek, line 3: unknown identifier noticed_syntax_error_F, at or near "noticed_syntax_error_F" +error in <...>/at-if-analyze-invalid.zeek, line 4: unknown identifier noticed_syntax_error_F, at or near "noticed_syntax_error_F" diff --git a/testing/btest/Baseline/language.at-if-analyze-invalid-5/out b/testing/btest/Baseline/language.at-if-analyze-invalid-5/out index 5e782bf157..ae863a3204 100644 --- a/testing/btest/Baseline/language.at-if-analyze-invalid-5/out +++ b/testing/btest/Baseline/language.at-if-analyze-invalid-5/out @@ -1,5 +1,5 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -error in <...>/at-if-analyze-invalid.zeek, line 6: record redef cannot appear inside @if &analyze -error in <...>/at-if-analyze-invalid.zeek, line 7: record redef cannot appear inside @if &analyze error in <...>/at-if-analyze-invalid.zeek, line 8: record redef cannot appear inside @if &analyze -error in <...>/at-if-analyze-invalid.zeek, line 9: enum redef cannot appear inside @if &analyze +error in <...>/at-if-analyze-invalid.zeek, line 9: record redef cannot appear inside @if &analyze +error in <...>/at-if-analyze-invalid.zeek, line 10: record redef cannot appear inside @if &analyze +error in <...>/at-if-analyze-invalid.zeek, line 11: enum redef cannot appear inside @if &analyze diff --git a/testing/btest/Baseline/language.at-if-analyze-invalid-6/out b/testing/btest/Baseline/language.at-if-analyze-invalid-6/out index bd6fac90b9..25306bb651 100644 --- a/testing/btest/Baseline/language.at-if-analyze-invalid-6/out +++ b/testing/btest/Baseline/language.at-if-analyze-invalid-6/out @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. warning in <...>/at-if-analyze-invalid.zeek, line 3: @if &analyze inside regular @if -error in <...>/at-if-analyze-invalid.zeek, line 8: unknown identifier but_a_syntax_error_here, at or near "but_a_syntax_error_here" +error in <...>/at-if-analyze-invalid.zeek, line 11: unknown identifier but_a_syntax_error_here1, at or near "but_a_syntax_error_here1" diff --git a/testing/btest/Baseline/language.at-if-analyze-invalid-7/out b/testing/btest/Baseline/language.at-if-analyze-invalid-7/out index c28ab5b982..31f7c69723 100644 --- a/testing/btest/Baseline/language.at-if-analyze-invalid-7/out +++ b/testing/btest/Baseline/language.at-if-analyze-invalid-7/out @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. warning in <...>/at-if-analyze-invalid.zeek, line 3: @if &analyze inside conditional -error in <...>/at-if-analyze-invalid.zeek, line 4: unknown identifier warning_and_noticed_syntax_err_F, at or near "warning_and_noticed_syntax_err_F" +error in <...>/at-if-analyze-invalid.zeek, line 7: unknown identifier warning_and_noticed_syntax_err_F, at or near "warning_and_noticed_syntax_err_F" diff --git a/testing/btest/Baseline/language.at-if-analyze-invalid-8/out b/testing/btest/Baseline/language.at-if-analyze-invalid-8/out index ff6f9b7873..af90888745 100644 --- a/testing/btest/Baseline/language.at-if-analyze-invalid-8/out +++ b/testing/btest/Baseline/language.at-if-analyze-invalid-8/out @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -warning in <...>/at-if-analyze-invalid.zeek, line 4: @if &analyze inside regular @if -error in <...>/at-if-analyze-invalid.zeek, line 9: unknown identifier but_a_syntax_error_here, at or near "but_a_syntax_error_here" +warning in <...>/at-if-analyze-invalid.zeek, line 5: @if &analyze inside regular @if +error in <...>/at-if-analyze-invalid.zeek, line 10: unknown identifier but_a_syntax_error_here, at or near "but_a_syntax_error_here" diff --git a/testing/btest/Baseline/language.at-if-analyze-invalid-9/out b/testing/btest/Baseline/language.at-if-analyze-invalid-9/out index 3eddb8eeff..2dd23936a3 100644 --- a/testing/btest/Baseline/language.at-if-analyze-invalid-9/out +++ b/testing/btest/Baseline/language.at-if-analyze-invalid-9/out @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -warning in <...>/at-if-analyze-invalid.zeek, line 5: @if &analyze inside conditional -error in <...>/at-if-analyze-invalid.zeek, line 6: unknown identifier warning_and_noticed_syntax_err_T, at or near "warning_and_noticed_syntax_err_T" +warning in <...>/at-if-analyze-invalid.zeek, line 6: @if &analyze inside conditional +error in <...>/at-if-analyze-invalid.zeek, line 7: unknown identifier warning_and_noticed_syntax_err_T, at or near "warning_and_noticed_syntax_err_T" diff --git a/testing/btest/Baseline/language.at-if-analyze-invalid/out b/testing/btest/Baseline/language.at-if-analyze-invalid/out index 7087da07db..af42fd93d7 100644 --- a/testing/btest/Baseline/language.at-if-analyze-invalid/out +++ b/testing/btest/Baseline/language.at-if-analyze-invalid/out @@ -1,3 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -error in <...>/at-if-analyze-invalid.zeek, line 7: @if &analyze cannot appear inside a function body -error in <...>/at-if-analyze-invalid.zeek, line 8: unknown identifier warning_and_noticed_syntax_error_T, at or near "warning_and_noticed_syntax_error_T" +error in <...>/at-if-analyze-invalid.zeek, line 8: @if &analyze cannot appear inside a function body +error in <...>/at-if-analyze-invalid.zeek, line 10: unknown identifier warning_and_noticed_syntax_error_T, at or near "warning_and_noticed_syntax_error_T" diff --git a/testing/btest/language/at-if-analyze-invalid.zeek b/testing/btest/language/at-if-analyze-invalid.zeek index de7a140f93..0c8cfedaf9 100644 --- a/testing/btest/language/at-if-analyze-invalid.zeek +++ b/testing/btest/language/at-if-analyze-invalid.zeek @@ -1,3 +1,4 @@ +# @TEST-DOC: Tests that @if/&analyze correctly validates code in non-activated branches # @TEST-EXEC: cat %INPUT # @TEST-EXEC-FAIL: zeek -b %INPUT >out 2>&1 # @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out @@ -5,6 +6,7 @@ event zeek_init() { @if ( T ) &analyze + # This should complain because it's inside a body warning_and_noticed_syntax_error_T @endif } @@ -14,6 +16,7 @@ event zeek_init() event zeek_init() { @if ( F ) &analyze + # This should also complain because it's inside a body warning_and_noticed_syntax_error_F @endif } @@ -21,12 +24,14 @@ event zeek_init() @TEST-START-NEXT @if ( T ) &analyze +# This should definitely complain ... noticed_syntax_error_T @endif @TEST-START-NEXT @if ( F ) &analyze +# ... and so should this, even though it's in a non-activated body noticed_syntax_error_F @endif @@ -36,6 +41,8 @@ type r: record { a: count; }; type e: enum { FOO }; @if ( F ) &analyze +# Try a bunch of forbidden redef's: adding a record field, adding/removing +# attributes, extending an enum. All should yield complaints. redef record r += { redef_disallowed_even_though_F: bool; }; redef record r$a += { &log }; redef record r$a -= { &log }; @@ -46,22 +53,29 @@ redef enum e += { redef_disallowed_even_though_F }; @if ( F ) @if ( T ) &analyze +# Generates a warning because of if-analyze inside a non-if-analyze - +# but doesn't then analyze the body. warning_and_unnoticed_syntax_err_T @endif @endif -but_a_syntax_error_here +# We add this to make sure there's *some* non-empty output. +but_a_syntax_error_here1 @TEST-START-NEXT @if ( T ) @if ( F ) &analyze +# In this case, both a warning for the mixed nesting *and*, because the +# outer conditional is true, a complaint since we go ahead with the +# if-analyze warning_and_noticed_syntax_err_F @endif @endif @TEST-START-NEXT +# Similar test but for "@else" branches. @if ( T ) @else @if ( F ) &analyze @@ -73,6 +87,7 @@ but_a_syntax_error_here @TEST-START-NEXT +# Similar test but for "@else" branches. @if ( F ) blah blah blah @else @@ -83,6 +98,7 @@ warning_and_noticed_syntax_err_T @TEST-START-NEXT +# Similar test but for "@else" branches. @if ( F ) blah blah blah @else diff --git a/testing/btest/language/at-if-analyze.zeek b/testing/btest/language/at-if-analyze.zeek index dd42858963..c875fad841 100644 --- a/testing/btest/language/at-if-analyze.zeek +++ b/testing/btest/language/at-if-analyze.zeek @@ -1,3 +1,4 @@ +# @TEST-DOC: Makes sure that code inside not-taken @if/&analyze blocks has its effects correctly unwound # @TEST-REQUIRES: test "${ZEEK_USE_CPP}" != "1" # @TEST-EXEC: zeek -b %INPUT >out # @TEST-EXEC: btest-diff out @@ -9,11 +10,12 @@ global redef_me = 0 &redef; @if ( nope ) &analyze redef nope = F; - event zeek_init() + event zeek_init() # this should not run { print "hi #1!", nope, redef_me; } + # Neither of these redef's should have lasting effect. @if ( nope ) &analyze redef redef_me = 1; @else @@ -24,7 +26,7 @@ global redef_me = 0 &redef; @if ( yep ) &analyze redef yep = F; global old_redef_me = redef_me; - event zeek_init() + event zeek_init() # this should run { print "hi #2!", yep, old_redef_me, redef_me; } @@ -32,7 +34,7 @@ global redef_me = 0 &redef; @if ( yep ) &analyze redef redef_me = 3; @else - redef redef_me = 4; + redef redef_me = 4; # we expect this, since we redef'd "yep" @endif @endif @@ -50,19 +52,23 @@ redef my_table: table[count] of string &default="redef #1"; @endif @if ( F ) &analyze +# Tricky - need to parse/validate the declaration, but not do the init global z = side_effects("shouldn't happen"); redef my_table: table[count] of string &default="redef #2"; @endif +# Okay, which &default did we actually pick up? print my_table[5]; @if ( T ) &analyze @if ( F ) &analyze print "T/F"; @else + # We expect this one print "T/!F"; @endif @else + # We expect none of these @if ( F ) &analyze print "!T/F"; @else @@ -71,6 +77,7 @@ print my_table[5]; @endif @if ( F ) &analyze + # We expect none of these @if ( F ) &analyze print "F/F"; @else @@ -78,6 +85,7 @@ print my_table[5]; @endif @else @if ( T ) &analyze + # We expect this one print "!F/T"; @else print "!F/!T";