JavaScript EditorFree JavaScript Editor     Perl Manuals 



Main Page

C.9. TclRobots.pm

Chapter 20, "IPC with send" discusses TclRobots in detail. TclRobots.pm allows you to write Robot Control Programs in Perl instead of Tcl.

$TclRobots::VERSION = '2.1';

package TclRobots;

# This module implements a thin API that interfaces Perl with tclrobots
# version 2, written by Tom Poindexter.  This means that you can write
# RCPs (Robot Control Programs) in your favorite language - Perl - and
# do battle with all the existing Tcl RCPs.
#
# This module is rather wierd - you're never supposed to use it!
# Instead, it's used when tclrobots runs an instance of perl, at which
# time this module is loaded and begins execution on behalf of your
# RCP.  It creates the main window of the required dimensions and at
# the proper location on the display, and adds all the widgets, text,
# and images
#
# When instructed by tclrobots, this module then loads your Perl RCP
# (via require, so be sure your code returns a TRUE value!), and the
# contest begins.  From that point on, incoming tclrobot messages are
# dispatched to Perl emulation handlers, and Perl RCP commands are
# converted to Tcl syntax and sent to tclrobots - the communication is
# via Tk::send() and Tk::Receive().
#
# Stephen.O.Lidie@Lehigh.EDU, 1999/05/07.
# Stephen.O.Lidie@Lehigh.EDU, 2000/04/13, for Perl 5.6.0.

use Exporter;
@ISA = qw/Exporter/;
@EXPORT = qw/after alert cannon damage dputs drive dsp heat loc_x loc_y
     scanner speed team_declare team_get team_send tick update/;

use File::Basename;
use Tk;
use Tk qw/after catch/;
use Tk::widgets qw/Dialog/;

use subs qw/_arrowshape__configure_widgets__customize_window_
     _disable_rcp__insult_rcp__destroy_rcp__load_rcp_
     _see_variable__set_variables__setup_window__start_rcp_/;
use vars qw/$_after_ $_alert_on_ $_debug $_dl_ $_fc_ $_fl_ $_fs_ $_mw_
     $_ping_proc_ $_rcp_filename_ $_resume_ $_robot_ $_start_ $_step_
     $_tclrobots_/;

use strict;

##############################################################################
#
# Note, we run tainted so that send() and receive() work.  Grab command line
# arguments:
#
# perl5 -Tw -I. -MTclRobots /dev/null RCP.ptr_2462 \
#     WidthxHeigh+X+Y rob2 tclrobots ./RCP.ptr
#
##############################################################################

return 1 if $ENV{TCLROBOTS_RCP_CHECK}; # if checking RCP syntax

$ENV{'HOME'} = '/tmp';
$_mw_ = MainWindow->new;
$_mw_->withdraw;

$ARGV[0] =~ /(.*)/;		# robot's Tcl name
$_mw_->appname($1);
$_mw_->title($1);

$ARGV[1] =~ /(.*)/;		# window geometry
$_mw_->geometry($1);

$ARGV[2] =~ /(.*)/;		# robot's handle
$_robot_ = $1;

$ARGV[3] =~ /(.*)/;		# tclrobot's name
$_tclrobots_ = $1;

$ARGV[4] =~ /(.*)/;		# RCP filename
$_rcp_filename_ = $1;

$_mw_->deiconify;
MainLoop;

##############################################################################
#
# Robot Control Program commands available to your Perl controlware.  For
# the most part, they simply invoke Tcl subroutines in tclrobots.  We also
# handle single stepping in Debug mode.
#
##############################################################################

{
     local $^W = 0;
     eval 'sub after {$_mw_->after(@_)}';
}

sub alert {
     my($code_ref) = @_;
     $_ping_proc_ = $code_ref;
     if (defined $code_ref) {
         $_alert_on_ = 1;
     } else {
         $_alert_on_ = 0;
     }
}

sub cannon {
     my($deg, $range) = @_;
     $_mw_->after(100);
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_cannon $_robot_ $deg $range");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     return $val;
}

sub damage {
     $_mw_->after(100);
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_damage $_robot_");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     return $val;
}

sub dputs {
     my(@args) = @_;
     $_resume_ = 0;
     Tk::catch {
         $_dl_->insert('end', join(' ', @args));
         $_dl_->yview('end'); $_mw_->update;
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     $_mw_->update;
}

sub drive {
     my($deg, $speed) = @_;
     $_mw_->after(100);
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_drive $_robot_ $deg $speed");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     return $val;
}

sub dsp {
     $_mw_->after(100);
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_dsp $_robot_");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     my(@dsp) = split(' ', $val);
     return @dsp;
}

sub heat {
     $_mw_->after(100);
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_heat $_robot_");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     my(@heat) = split(' ', $val);
     return @heat;
}

sub loc_x {
     $_mw_->after(100);
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_loc_x $_robot_");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     return $val;
}

sub loc_y {
     $_mw_->after(100);
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_loc_y $_robot_");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     return $val;
}

sub scanner {
     my($deg, $res) = @_;
     $_mw_->after(100);
     $_mw_->after(100);
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_scanner $_robot_ $deg $res");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     return $val;
}

sub speed {
     $_mw_->after(100);
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_speed $_robot_");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     return $val;
}

sub team_declare {
     my($tname) = @_;
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_team_declare $_robot_ $tname");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     return $val;
}

sub team_get {
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_team_get $_robot_");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     my @teams;
     foreach my $team (&SplitString($val)) {
         my($dsp, $data) = split ' ', $team;
         push @teams, [$dsp, $data];
     }
     return @teams;
}

sub team_send {
     my($args) = @_;
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_team_send $_robot_ \"$args\"");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     return $val;
}

sub tick {
     $_mw_->after(100);
     $_mw_->update;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_tick $_robot_");
     };
     $_mw_->waitVariable(\$_resume_) if $_debug and $_step_;
     &_ping_check_;
     $_mw_->update;
     return $val;
}

sub update {
     $_mw_->update;
}

##############################################################################
#
# Tcl -> Perl handlers.
#
##############################################################################

sub Tk::Receive {

     # Accept Tcl strings from tclrobots and invoke
     # Perl/Tk emulation code.

     my($mw) = shift;		# main window
     $_ = shift;			# Tcl command

     return 2 if /expr 1\+1/;
     return if /(Knuth|^rename)/m;

   CASE:
     {
         /setup window/m    and do {_setup_window_;        last CASE};
         /create|configure/ and do {_customize_window_ $_; last CASE};
         /set _start_ 0/    and do {_load_rcp_;            last CASE};
         /set _start_ 1/    and do {_start_rcp_;           last CASE};
         /^proc after/      and do {_disable_rcp_;         last CASE};
         /\.d\.l insert/    and do {_insult_rcp_ $_;       last CASE};
         /^_a_\d+ 0 _e_\d+/ and do {_destroy_rcp_;         last CASE};
         /^set/             and do {_set_variables_ $_;    last CASE};
         /^format/          and do {return _see_variable_ $_;};
         print STDERR "UNHANDLED cmd=$_!\n";
     } # casend

} # end Tk::Receive

sub _arrowshape_ {
     my($cmd) = @_;
     my($cs, $ar) = $cmd =~ /\.f\.. create (.*) (-arrowshape.*)/;
     my(@cs) = split(' ', $cs);
     $ar =~ /"(\d+) (\d+) (\d+)/;
     my $as = [$1, $2, $3];
     $_fc_->create(@cs, -arrowshape => $as);
}

sub _configure_widgets_ {
     my($cmd) = @_;
     my($w) = $cmd =~ /\.f\.l/ ? $_fl_ : $_fs_;
     my($cs) = $cmd =~ /configure (.*)/;
     $cs =~ s/(;.*)//;
     my(@cs) = split(' ', $cs);
     $w->configure(@cs);
     $w->update;
}

sub _customize_window_ {
     $_ = $_[0];
     /configure/ and do {_configure_widgets_ $_; return};
     /create/    and do {_arrowshape_ $_;        return};
}

sub _destroy_rcp_ {
     $_mw_->after(1 => $_mw_->destroy);
}

sub _disable_rcp_ {
     {
         local $^W = 0;
         eval 'sub after {}';
         eval 'sub _ping_check_ {
             while (1) {
                 $_mw_->update;
                 $_mw_->after(100);
             }
         }';
     }
}

sub _insult_rcp_ {
     my($cmd) = @_;
     my($text) = $cmd =~ /insert end(.*)?;\.d\.l/;
     $_mw_->after(1 => sub {
         $text =~ s/\\//g;
         $_dl_->insert('end', $text);
         $_dl_->yview('end');
         $_mw_->update;
         $_mw_->waitWindow;
     });
}

sub _load_rcp_ {
     $_start_ = 0;
     $_mw_->after(100 => sub {
         $_mw_->waitVariable(\$_start_);
         eval "require \"$_rcp_filename_\"";
         if ($@) {
             my $bn = basename $_rcp_filename_;
             my $d = $_mw_->Dialog(
                 -title => $_mw_->appname,
                 -text  => "$@\nYour RCP failed to compile. To perform a 
syntax " .
                   "check, do:\n\nTCLROBOTS_RCP_CHECK=1 perl -MTclRobots $bn",
                 -font  => 'fixed');
             $d->Subwidget('message')->configure(-wraplength => '8i');
             $d->Show;
             $d->destroy;
         }
     });
}

sub _see_variable_ {
     my($expression) = @_;	# including leading $
     $expression = substr $expression, 8;
     {
         no strict;
         # Perl bug: I want eval "$expression";
         # So for now, assume a scalar var name.
         $$expression;
     }
}

sub _setup_window_ {

     # Setup the RCP's debug and damage window.

     my $f = $_mw_->Frame;
     $f->pack(qw/-side top -fill x -ipady 5/);
     $_fc_ = $f->Canvas(qw/-width 20 -height 16/);
     $_fl_ = $f->Label(qw/-relief sunken -width 30  -text/ =>
                       "(loading robot code..)");
     $_fs_ = $f->Label(qw/-relief sunken -width 5   -text/ => "0%");
     $_fc_->pack(qw/-side left/);
     $_fs_->pack(qw/-side right/);
     $_fl_->pack(qw/-side left -expand 1 -fill both/);

     $_dl_ = $_mw_->Scrolled('Listbox', qw/-relief sunken -scrollbars se/);
     $_dl_->pack(qw/-side left  -expand 1 -fill both/);
     $_mw_->minsize(100, 70);
     $_mw_->update;

     $_resume_ = 0;
     $_step_ =  0;

}

sub _set_variables_ {
     my($cmd) = @_;
     foreach (split /;/, $cmd) {
         my($set, $var, $val) = /(set)\s+(\S+)\s+(.*)/;
         {no strict; eval {$$var = $val}}
     }
}

sub _start_rcp_ {
     $_mw_->after(100 => sub {$_start_ = 1});
}

##############################################################################
#
# Auxiliary routines.
#
##############################################################################

$_ping_proc_ = '';
$_alert_on_ = 0;
sub _ping_check_ {
     return unless $_alert_on_;
     my $val = Tk::catch {
         $_mw_->send($_tclrobots_, "do_ping $_robot_");
     };
     Tk::catch {&$_ping_proc_($val)} if $val != 0;
}

sub SplitString {

     # Swiped from Tk800.015 distribution - a weak attempt to
     # turn a Tcl LOL into a Perl LOL.

     local $_ = shift;
     my (@arr, $tmp);

     while (/\{([^{}]*)\}|((?:[^\s\\]|\\.)+)/gs) {
         if (defined $1) {
             push @arr, $1;
         } else {
             $tmp = $2 ;
             $tmp =~ s/\\([\s\\])/$1/g;
             push @arr, $tmp;
         }
     }
     return @arr;
} # end SplitString

1;





JavaScript EditorJavaScript Formatter     Perl Manuals


©