Language-Basic

 view release on metacpan or  search on metacpan

lib/Language/Basic/Statement.pm  view on Meta::CPAN

    $self->{"expression"} = new Language::Basic::Expression::Arithmetic $token_group
        or Exit_Error("Bad expression in GOTO!");
} # end sub Language::Basic::Statement::Goto::parse

# Note that this sub allows "GOTO X+17/3", not just "GOTO 20"
sub implement {
    my $self = shift;
    my $prog = &Language::Basic::Program::current_program;
    my $goto = $self->{"expression"}->evaluate;
    if ($goto !~ /^\d+$/) {Exit_Error("Bad GOTO: $goto")}
    $prog->goto_line($goto);
} # end sub Language::Basic::Statement::Goto::implement

sub output_perl {
    my $self = shift;
    # if it's just a number , don't use $tmp
    my $exp = $self->{"expression"};
    my $goto = $exp->output_perl;
    my $ret;
    if ($goto =~ /^\d+$/) {
        $ret = "goto L$goto;";
    } else {
	# Form the label name
	$ret = "\$Goto_tmp = 'L' . " . $goto . ";\n";
	# Go to it
	$ret .= "goto \$Goto_tmp;";
    }

    return ($ret);
} # end sub Language::Basic::Statement::Goto::output_perl
} # end package Language::Basic::Statement::Goto

######################################################################
# package Language::Basic::Statement::If
# An IF statement in a BASIC program.
{
package Language::Basic::Statement::If;
@Language::Basic::Statement::If::ISA = qw(Language::Basic::Statement);
use Language::Basic::Common;

sub parse {
    my $self = shift;
    my $token_group = shift;

    # Until the token "then", we're copying a conditional expression
    my $exp = new Language::Basic::Expression::Logical_Or $token_group or
        Exit_Error("Bad Condition in IF!");
    $self->{"condition"} = $exp;
    $token_group->eat_if_string("THEN") or Exit_Error("IF missing 'THEN'!");

    # Until the token "ELSE" or the end of the line, is one or more
    # statements to do if the IF is true
    # TODO we need to handle ELSE either within the same statement
    # as the last THEN statement *OR* at the beginning of a statement.
    # Also nested IFs?

    # Take everything up to ELSE into a separate Token::Group &
    # call parsing with that so that other parse routines can complain if
    # there's something left in their token_group. Right now, they'll have
    # problem with ELSE token
    # TODO need a Token::Group::split method or some such
    my $t1 = new Language::Basic::Token::Group;
    $t1->slurp($token_group, "ELSE");

    # Call new with an extra arg so it knows it's parsing a THEN/ELSE.
    # That way, "THEN 20" gets parsed like "THEN GOTO 20"
    my $then = new Language::Basic::Statement $t1, "line_num_ok" or
	Exit_Error("No statement found after THEN");
    $then->parse($t1);
    my $oldst = $then;
    # Eat [: Statement]*
    while (defined($t1->eat_if_class("Statement_End"))) {
	# Plain line number is only allowed in the *first* THEN/ELSE statement
	my $st = new Language::Basic::Statement $t1;
	$st->parse($t1);
	$oldst->{"next_statement"} = $st;
	$oldst = $st;
    }
    # Make sure we don't do the ELSE after the THEN!
    $oldst->{"next_statement"} = undef;

    # If there's anything left in $token_group, it's the ELSE.
    my $else;
    if (defined($token_group->eat_if_string("ELSE"))) {
	# Use up all the leftover tokens
	$else = new Language::Basic::Statement $token_group, "line_num_ok" or
	    Exit_Error("No statement found after THEN");
	$else->parse ($token_group);
	$oldst = $else;
	while (defined($token_group->eat_if_class("Statement_End"))) {
	    my $st = new Language::Basic::Statement $token_group;
	    $st->parse($token_group);
	    $oldst->{"next_statement"} = $st;
	    $oldst = $st;
	}
	$oldst->{"next_statement"} = undef;
	Exit_Error("Unknown stuff after ELSE statement(s)") if 
	    $token_group->stuff_left;
    } else {
	Exit_Error("Unknown stuff after THEN statement(s)") if 
	    $token_group->stuff_left;
    }

    $self->{"then_s"} = $then;
    $self->{"else_s"} = $else; # may be undef
} # end sub Language::Basic::Statement::If::parse

# Need to set line numbers for THEN and ELSE statements, so we can't
# use the default LBS::set_line_number
sub set_line_number {
    my $self = shift;
    my $num = shift;
    $self->{"line_number"} = $num;
    foreach ("then_s", "else_s") {
        my $st = $self->{"$_"};
	while (defined $st) {
	    $st->set_line_number($num);
	    $st = $st->{"next_statement"};
	}
    }
}



( run in 0.464 second using v1.01-cache-2.11-cpan-71847e10f99 )