Please send questions to st10@humboldt.edu .
#!/usr/bin/perl -w

#######################################################
# expr_play
#
# try to permit a student to "play" with simple
# C++ expressions including calls to functions they have
# already written and compiled. THIS VERSION DOES *NOT*
# SUBMIT ANY RECORD TO THE COURSE DROP BOX DIRECTORY.
# 
# ASSUMPTIONS:
#    * you are running this under UNIX/Linux/OS X (or compatible
#      environments); it was developed for use on Humboldt's 
#      cs-server.humboldt.edu
#    * you have set $instr_username below to be your local username
#      (for submitting to the drop-box-directory in your account
#      appropriately)
#    * you have set $course variable below to be the "nickname" 
#      for your course (e.g., cis130)
#      
# written by: Sharon M. Tuttle, st10@humboldt.edu
# last modified:03-03-10 - trying to add in return EXIT_SUCCESS
#                          to little main built (to make it a
#                          better example, JUST in case...)
#               10-15-09 - trying to "build in" boolalpha, so get
#                          true, false to output as true, false
#                          (not 1, 0)
#               10-16-08 - trying to fix pwd, now broken after move
#                          to nrs-labs?! ALSO not deleting little
#                          program created, for now -- maybe a useful
#                          example?
#                          
#               10- 9-07 - changed course name to CS 131
#                4-02-07 - version that DOESN'T submit...
#                7-21-05 - perhaps SUBMIT the file, instead?
#                          using a "special" ${course}submit_embeddable?
#                6-05-05 - emailing portion commented out
#                9-17-03 - NOW HANDLES BOOL EXPR'S BETTER! 
#######################################################

my $tool_name = "expr_play";
my $version = "03-03-10";
my $course = "cis130";
my $instr_username = "st10";

#----------------------------------------------------------
# subroutine to ensure that a y or n answer is given
#----------------------------------------------------------

sub get_y_or_n
{
    chomp(my $response = <STDIN>);

    while (($response ne "y") && ($response ne "n"))
    {
        print "please respond with y or n: ";
        chomp($response = <STDIN>);
    }

    return $response;
}

#------------------------------------------------------------------
# subroutine to finish up the message-to-be-submitted (record of student's
#    use of this tool) 
# (1 parameter: a message you'd like to add to the end of the
#    student's record before it is submitted)
#------------------------------------------------------------------

sub finish_record
{
    my($closing_note) = @_;
}


#-----
# PART 1: setting up the beginning of a record
# of the student's use of this script;
#-----

use File::Basename;

print "----------------------------------------------\n";
print "Welcome to the $version version of $tool_name!\n";
print "----------------------------------------------\n";

# grab info about who, where, and when for this execution ---
#    to be included in email to me...

chomp(my $who = `whoami`);
# why did these lines start failing when moved to nrs-labs in F08?!
#    good thing I don't use them later after all...!
#chomp(my $where_path = `pwd`);
#my $where = basename $where_path;

chomp(my $start_time = `date`);

#-----
# PART 2: set up initial variables to help with compiling
# the eventual test program to be generated
#-----

# at this point, I know that certain #include's will be necessary for
# the eventual test program generated by this Perl script. I'll start
# these here, so that I can add to it if the user wants to use 
# functions they've defined previously in the new function.

my $include_stmts = "#include <iostream>\n#include <cmath>\n";
# removed 03-03-10 -- print at end whenever use
#                    . "using namespace std;\n\n";

# for debugging purposes...
#print "initial \#include statements:\n";
#print "--------------------------\n";
#print "$include_stmts";
#print "--------------------------\n"; 

# Will additional .o files be needed for the compilation of the eventual
#    test program? Just in case, start that empty string here;
my $addl_obj_files = "";

# for debugging purposes...
#print "initial .o files:\n";
#print "--------------------------\n";
#print "$addl_obj_files\n";
#print "--------------------------\n"; 

#-----
# PART 3: Are there any existing functions (currently limited
# to the current working directory) that the student wishes to
# be able to use in his/her new function? If so, get their names
# from the student, and set up what is required for their use
# in the new function to come.
#-----

print "\n";
print "Are there any already-created C++ functions (in the current \n";
print "   working directory) which you would like to be able to use\n";
print "   within C++ expressions?\n";
print "   (type y if so, n if not)\n";
print "your answer: ";

my $reply = &get_y_or_n();

# get the names of already-created functions, set up for their use in
# the new function to come

my $other_desired_funct_names = "";

if ($reply eq "y")
{
    print "\n";
    print "*********************************************************\n";
    print "NOTE: to test a function A, you need to give the names\n";
    print "   of ALL functions that A uses, as well as those that\n";
    print "   THEY use --- otherwise, the tests will fail.\n";
    print "(that is, you may have to give all functions in the \n";
    print "   PROGRAM...)\n"; 
    print "**********************************************************\n";

    print "\n";
    print "Enter the name of an already-created function (created in the\n";
    print "   current directory), or q to quit:\n";
    print "function name: ";

    chomp(my $old_funct = <STDIN>);

    while ($old_funct ne "q")
    {
        my $old_funct_source = "${old_funct}\.cpp";
        my $old_funct_hdr = "${old_funct}\.h";

        # make sure that the source code for this function exists
        if (! -e $old_funct_source)
	{
            print "\n";
            print "   There is no source code file $old_funct_source\n";
            print "      for function $old_funct; this function cannot\n";
            print "      be used in your new function.\n";
            print "\n";            
	}
        
        # make sure that the header file for this function exists
        elsif (! -e $old_funct_hdr)
	{
            print "\n";
            print "   There is no header file $old_funct_hdr\n";
            print "      for function $old_funct; this function cannot\n";
            print "      be used in your new function.\n";
            print "\n";            
	}

        else 
        {
            # if reach here, BOTH the .cpp and .h files exist for 
            #    this function;

            # IF there is not currently a .o file for this function,
            #    attempt to create one;
            if (! -e "${old_funct}\.o")
            {
                my $ret_val = system("g++ -c $old_funct_source");

                if (($ret_val != 0) || (! -e "${old_funct}\.o"))
		{
                    print "\n";
                    print "Beware --- there was a problem trying to create\n";
                    print "   a .o file for $old_funct.\n";
                    print "\n";
		}
            }

            # at this point, either a .o file exists for this
            #    function, or we have attempted to create one;
   
            # add #include for this function to those for eventual
            #    test program for new function
            $include_stmts .= "#include \"$old_funct_hdr\"\n";

            # add object file for this function for use in eventual
            #    compilation of eventual test program for new function
            $addl_obj_files .= "${old_funct}\.o ";

            # add name for this function for use to list in possible-
            #    functions when testing later
            $other_desired_funct_names .= "\n$old_funct";            

#            $header_guts = `cat ${old_funct}.h`;
#            $funct_guts = `cat ${old_funct}.cpp`;
        }

        print "\n";
        print "Enter the next name of an already-created function (created\n";
        print "   in the current directory), or q to quit:\n";
        print "function name: ";

        chomp($old_funct = <STDIN>);
    }
}

# print statements verifying that DID build desired #includes and .o
#    based on old functions student wants new function to be able to use
#
#print "\n";
#print "AFTER old-funct loop, here are the resulting include statements\n";
#print "and object files:\n";
#
#print "newest set of \#include statements:\n";
#print "--------------------------\n";
#print "$include_stmts";
#print "--------------------------\n"; 
#
#print "newest set of .o files:\n";
#print "--------------------------\n";
#print "$addl_obj_files\n";
#print "--------------------------\n"; 

#-----
# PART 6: enter desired expressions? OR build a program that asks for
#    each parameter, and then dynamically calls? (Might the latter be more
#    efficient? Each new "expr" using the function then wouldn't require
#    another recompile! But, gotta parse out # of arguments --- that's
#    for next version, I think.)
#----- 

#
# question: actually include the function within the main(), or #include
# a .h file for it? But for the latter, I'd need to create a .h as well 
# as a .cpp for each function, and then change the compilation command
# accordingly; hmm.
#
# hm; first, let's just paste the raw code in.
# to do this, I can solicit the header and body, put it in a .cpp file
#    named based on the function name, and then use the header to build
#    the function definition, and the .cpp file to build the function
#    declaration after main() --- right?
# (wonder how slow this'll be? shudder...)
#
# (and I may just #include it, after all, after looking at multi-file
#    example in c++_reference directory. Hmm.)
#
# IF they give me a header --- CAN a function declaration include parameter
#     names? Can a .h file? (Is this not required, or not allowed?)

# the student must enter the purpose statement for their function
#    first --- might this get them into the habit of coming up
#    with a purpose statement early on? It's worth a shot...

# now that all is set up --- permit expressions to be
# entered for evaluation (hopefully including some
# involving the newly-created functions!)

print "\n";
if ("$other_desired_funct_names" eq "")
{
    print "Enter a C++ expression, and type enter\n";
}
else
{
    print "Enter a C++ expression involving:" . 
          "$other_desired_funct_names" .
          "\n...and type enter\n";
}
print "   (or type q to quit):\n";

chomp(my $expr = <STDIN>);

# shall we create each expression's program in a separate file,
#    or not? Hmm... For now, yes.

my $expr_ct = 0;

# keep handling expressions until the user wishes to quit

while ($expr ne 'q')
{
    print "\n";
    $expr_ct++;

    # create a C++ program to execute this expression
    open TESTER, "> try_expr$expr_ct.cpp"
        or die "Cannot open try_expr$expr_ct.cpp for writing: $!";

    # this will include other functions they've mentioned wanting
    #    to use --- is that okay? THEN need to tack new function's
    #    .h file, too!
    print TESTER "$include_stmts";
    print TESTER "using namespace std;\n";

    print TESTER "\n";
    print TESTER "int main()\n";
    print TESTER "{\n";
    print TESTER "    cout << boolalpha;\n";

    # be careful if this is a string expression...!
    if ($expr =~ /".*"/)
    {
        print TESTER "    cout << \"value of \" << $expr 
                               << \": \" << endl;\n";
    }
    else
    {
        print TESTER "    cout << \"value of $expr: \" << endl;\n";
    }
    print TESTER "    cout << ($expr) << endl;\n";
    print TESTER "\n";
    print TESTER "    return EXIT_SUCCESS;\n";
    print TESTER "}\n";
    print TESTER "\n";

    close TESTER;

    # this need to include .o file for new function, doesn't it?
    my $ret_val = system("g++ -o try_expr$expr_ct try_expr$expr_ct.cpp " . 
                         "$addl_obj_files");

    # I am hoping very hard that a return value of 0 means the compilation
    #    was successful;
    if ($ret_val == 0)
    {
        # had to add the ./ to get this to work on nrs-labs, F08?!
        system("./try_expr$expr_ct");
    }
    else
    {
        print "*****************************************************\n";
        print "Are you sure that $expr is truly a C++ arithmetic\n";
        print "   expression (with no variables)?\n";
        print "Chances are good that it is not; the above are C++\n";
        print "   compiler messages. Save them and show them to \n";
        print "   your prof if you have questions.\n";
        print "*****************************************************\n";
    }

    # save a record of this attempt (to be submitted to me at the
    #    end of this loop...)
    my $when = `date`;

    # clean up --- remove latest expression's C++ files
# 10-16-08 - COMMENTING OUT for now -- maybe resulting file is an
# interesting example?
#    unlink "try_expr$expr_ct.cpp";
#    if ($ret_val == 0)
#    {
#        unlink "try_expr$expr_ct";
#    }

    print "\nEnter next C++ expression and type enter\n";
    print "   (or type q to quit):\n";
    chomp($expr = <STDIN>);
}   

&finish_record("reached end of $tool_name script");

print "\nQuitting $tool_name ... goodbye.\n\n";

# end of expr_play