AT has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I am having a strange problem with expect.pm which hopefully others have encountered. I have set up my own prompt and do some checking and send a command to another program, I expect to wait for the result and display it before moving to the next prompt but I get my prompt back much earlier and after giving 1 to 2 more inputs, I get the previous result back. If I make it very simple, no subroutines, checks etc, I suppose it works fine. **using debugging, it seems somehow I am getting extra prompts from called program (due to longer wait?) and so expect matches and goes on!** I used the recommended settings to get a pipe-like behaviour. 2) Is there a simpler way I can just have a running program in the background, give it input, fetch output and display it back on stdout, besides using expect. the cleaned up code is somewhat like this:
$mapfile="toy2.map"; $outfile="toy2.smv"; open(spcmap,"<",$mapfile) || die("Couldn't read $mapfile: $!"); expectsmv(); close($mapfile); sub expectsmv { my $exp = new Expect; my ($bout, $aout, $err); $exp->log_stdout(0); $exp->raw_pty(1); $exp->manual_stty(1); my $command="NuSMV -int"; $exp->spawn($command) or die "Cannot spawn $command: $!\n"; #$exp->log_file("expect_log"); # Remove the banner # $exp->send("\n"); my $patidx = $exp->expect(undef,'NuSMV > ', '-re','NuSMV\s+>\s+' ); #$exp->clear_accum(); #Setup NuSMV and load model file $exp->send("read_model -i $outfile \n"); $exp->send("process_model \n"); #$err = $exp->error; #if($err != 0){ print "Error=", $err ;} #$exp->clear_accum(); while(1) { print "B2S > "; my $cmd = <STDIN>; if($cmd =~ /\s*quit\s+/){ last; $exp->soft_close(); } elsif($cmd =~ /\s*query\s+./) { my($q, $c) = split(" ",$cmd,2); #$cmd = nusmv_q_trans($c); chomp($cmd); $exp->clear_accum(); if($cmd !~ /\b*error1\b*/){ $cmd = "check_spec -p \" $cmd \" "; print "\n $cmd \n"; $exp->send($cmd);} else { print "\n Error \n"; } #Do some pattern matching with either the simple interface my $patidx = $exp->expect(undef,'NuSMV > ', '-re','NuSMV\s+>\s+' ); $err = $exp->exp_error(); if($err != 0){ print "Error=", $err ;} else{ # print $patidx; ($bout = $exp->exp_before) =~ tr/\r//d; $err = $bout; #$bout = nusmv_res_trans($bout); print $bout; } } # end of elsif else # Not a Query { $exp->send($cmd); my $patidx = $exp->expect(undef,'NuSMV > ', '-re','NuSMV\s+>\s+' ); $err = $exp->exp_error; if($exp->error() != 0){ print $exp->error(); last;} else{ ($bout = $exp->exp_before) =~ tr/\r//d; ($aout = $exp->exp_after) =~ tr/\r//d; print $bout; } } #end of else } $exp->clear_accum(); } #end of subroutine #Routine for Translating Query into nusmv format sub nusmv_q_trans { my ($cmd) = @_; #change species names to bngl S# format # search for a species name; beginning with alphabet and replace with +S# found from hash print $cmd; #$cmd =~ s/\b([a-zA-Z])\w*\b/S$smap{$1} /g; $cmd =~ s{ \b([a-zA-Z])\w*\b } { $smap{$1} ? "S$smap{$1}" : return "error1" }xge; $cmd =~ tr/_//d; return $cmd; } sub nusmv_res_trans { my ($res) = @_; $res =~ s/\bS(\d+)\b/$spar[$1]/g; return $res; }
here' the debug code:
B2S > help Sending 'help \012' to spawn id(4) Expect::print('Expect=GLOB(0x98195cc)','help \x{a}') called at + ./expecttest.pl line 96 main::expectsmv() called at ./expecttest.pl line 7 Starting EXPECT pattern matching... Expect::expect('Expect=GLOB(0x98195cc)',10000,'NuSMV > ','-re' +,'NuSMV\s+>\s+') called at ./expecttest.pl line 99 main::expectsmv() called at ./expecttest.pl line 7 spawn id(4): list of patterns: #1: -ex `NuSMV > ' #2: -re `NuSMV\\s+>\s+' spawn id(4): Does `' match: pattern #1: -ex `NuSMV > '? No. pattern #2: -re `NuSMV\\s+>\s+'? No. Waiting for new data (10000 seconds)... spawn id(4): Does `NuSMV > ' match: pattern #1: -ex `NuSMV > '? YES!! Before match string: `' Match string: `NuSMV > ' After match string: `' Matchlist: () Returning from expect successfully. B2S > Sending ' \012' to spawn id(4) Expect::print('Expect=GLOB(0x98195cc)',' \x{a}') called at ./e +xpecttest.pl line 96 main::expectsmv() called at ./expecttest.pl line 7 Starting EXPECT pattern matching... Expect::expect('Expect=GLOB(0x98195cc)',10000,'NuSMV > ','-re' +,'NuSMV\s+>\s+') called at ./expecttest.pl line 99 main::expectsmv() called at ./expecttest.pl line 7 spawn id(4): list of patterns: #1: -ex `NuSMV > ' #2: -re `NuSMV\\s+>\s+' spawn id(4): Does `' match: pattern #1: -ex `NuSMV > '? No. pattern #2: -re `NuSMV\\s+>\s+'? No. Waiting for new data (10000 seconds)... spawn id(4): Does `NuSMV > ' match: pattern #1: -ex `NuSMV > '? YES!! Before match string: `' Match string: `NuSMV > ' After match string: `' Matchlist: () Returning from expect successfully. B2S > Sending ' \012' to spawn id(4) Expect::print('Expect=GLOB(0x98195cc)',' \x{a}') called at ./e +xpecttest.pl line 96 main::expectsmv() called at ./expecttest.pl line 7 Starting EXPECT pattern matching... Expect::expect('Expect=GLOB(0x98195cc)',10000,'NuSMV > ','-re' +,'NuSMV\s+>\s+') called at ./expecttest.pl line 99 main::expectsmv() called at ./expecttest.pl line 7 spawn id(4): list of patterns: #1: -ex `NuSMV > ' #2: -re `NuSMV\\s+>\s+' spawn id(4): Does `' match: pattern #1: -ex `NuSMV > '? No. pattern #2: -re `NuSMV\\s+>\s+'? No. Waiting for new data (10000 seconds)... spawn id(4): Does `... \012gen_ltlspec_bmc_onepb get_internal_st +atus go \012go_bmc goto_st +ate help \012history pick_s +tate print_bdd_stats \012print_clusterinfo pri +nt_current_state print_fair_states \012print_fair_trans +itions print_iwls95options print_reachable_states \012pri +nt_usage process_model quit + \012read_model read_trace reset + \012set set_bdd_parameters + show_plugins \012show_property show_trace +s show_vars \012simulate + source time \012unalias + unset usage \ +012which write_boolean_model write_flat_mod +el \012write_order \012' match: pattern #1: -ex `NuSMV > '? No. pattern #2: -re `NuSMV\\s+>\s+'? No. Waiting for new data (10000 seconds)... spawn id(4): Does `...en_ltlspec_bmc_onepb get_internal_status + go \012go_bmc goto_state + help \012history p +ick_state print_bdd_stats \012print_clusteri +nfo print_current_state print_fair_states \012p +rint_fair_transitions print_iwls95options print_reachable_states + \012print_usage process_model quit + \012read_model read_trace reset + \012set set_bdd_parameters sho +w_plugins \012show_property show_traces + show_vars \012simulate source + time \012unalias uns +et usage \012which + write_boolean_model write_flat_model \012write_orde +r \012NuSMV > ' match: pattern #1: -ex `NuSMV > '? YES!! Before match string: `... \012gen_ltlspec_bmc_onepb get_inte +rnal_status go \012go_bmc + goto_state help \012history + pick_state print_bdd_stats \012pri +nt_clusterinfo print_current_state print_fair_states + \012print_fair_transitions print_iwls95options print_r +eachable_states \012print_usage process_model + quit \012read_model read_tr +ace reset \012set + set_bdd_parameters show_plugins \012show_pr +operty show_traces show_vars + \012simulate source time \0 +12unalias unset usage \012w +hich write_boolean_model write_flat_model \012writ +e_order \012' Match string: `NuSMV > ' After match string: `' Matchlist: () Returning from expect successfully. add_property alias bmc_setup bmc_simulate build_boolean_model build_flat_model build_model check_fsm check_invar check_invar_bmc check_ltlspec check_ltlspec_bmc check_ltlspec_bmc_onepb check_property check_spec check_wff compute compute_reachable dynamic_var_ordering echo encode_variables flatten_hierarchy gen_invar_bmc gen_ltlspec_bmc gen_ltlspec_bmc_onepb get_internal_status go go_bmc goto_state help history pick_state print_bdd_stats print_clusterinfo print_current_state print_fair_states print_fair_transitions print_iwls95options print_reachable_st +ates print_usage process_model quit read_model read_trace reset set set_bdd_parameters show_plugins show_property show_traces show_vars simulate source time unalias unset usage which write_boolean_model write_flat_model write_order B2S >
AT

Replies are listed 'Best First'.
Problem with expect.pm
by AT (Initiate) on Jul 13, 2005 at 17:44 UTC
    Hi, I am having a strange problem with expect.pm which hopefully others have encountered. I have set up my own prompt and do some checking and send a command to another program, I expect to wait for the result and display it before moving to the next prompt but I get my prompt back much earlier and after giving 1 to 2 more inputs, I get the previous result back. If I make it very simple, no subroutines, checks etc, I suppose it works fine. I used the recommended settings to get a pipe-like behaviour. 2) Is there a simpler way I can just have a running program in the background, give it input, fetch output and display it back on stdout, besides using expect. the cleaned up code is somewhat like this: AT

    20050713 ysth: reparented this original question under follow that had more info

Re: expect.pm problem
by graff (Chancellor) on Jul 14, 2005 at 03:32 UTC
    Whew. This is rather a difficult mess to attack. Find out if the text editor you are using to write programs has any sort of facility for doing auto-indentation, so that it's easy to make sure that blocks of code are properly indented. If your current editor doesn't support this, look for an editor that does.

    I don't actually have Expect.pm installed on my machine at the momemnt, but even if I did, I'd have no way to test your code for myself. Still, after editing a copy of it to apply proper indentation, the following points became evident:

    • You need to include "use strict" and "use warnings"

    • You don't seem to understand the "open" and "close" calls. The first argument to open() should either be the name you want to assign to a filehandle, in CAPS (e.g. SPCMAP, not spcmap), or else it should be a scalar variable with lexical scope:  open my $spcmap, '<', $mapfile or die ... Then, the close() call needs to be given the FILEHANDLE (i.e. first arg given to open()) -- not the name of the file that was opened.

    • You don't seem to understand quantifiers and/or the "\b" operator in regular expressions; in your regex:  /\b*error1\b*/ the "*" quantifier makes no sense when applied to the "zero-width word-boundary assertion".

    • Inside your while(1) loop, you read a command from STDIN, and you do one of three things depending on its content: the first thing is exit the loop if "quit " occurs anywhere in the string (no problem there); the second involves some other checks and mods -- including  chomp $cmd; and the third involves just passing $cmd to expect->send() -- without chomping it. I wonder if that might be part of the problem (I really don't know.)

    Apart from that, I have no way of knowing what might be wrong. But you may want to see whether IPC::Open2 or IPC::Open3 could do what needs to be done -- they are part of the core distribution, and may be simpler to use than Expect.

    update: one other point of confusion -- you have those two "nusmv_*" subroutines defined at the bottom of the code, but the calls to these subroutines are commented out. I suppose this is an intentional part of you debugging efforts, but if skipping those calls is part of the problem, you're the only one who can figure that out (not us); if skipping the calls has no effect on the program's behavior, why include them in the post?

      Sorry for the en-masse violation of writing ethics! I was trying to give a smaller portion from the main code and so it became messy. All suggestions accepted and implemented. Here is what I figured out but which hasnt helped me solve it:
      Looking at the debug code, the problem occurs when the called program (NuSMV) is taking longer time ~0.3 seconds to give the result. Somehow spurious or extra input (i.e. NuSMV prompts, 'NuSMV >') are coming back to expect in the meanwhile, and accepting that, it moves on. I cant figure out why this is happening. If it takes less time ~0.0 secs (NuSMV gives a timer), there is no problem.

      Regd Open: I tried some stuff but not clear on the std I/O operations. here is the problem. A accepts input from user, passes that input to B (A' stdout -> B's stdin?), B processes, gives the result back (B's stdout -> A's stdin?), A displays the result back (A' stdout -> monitor). (Who's the reader, who is the writer? )
      I suppose this should be rather straightforward for pipe gurus ;-) - can you suggest code on this.

      thanks, AT