#!/applic/nir/sun4/bin/perl -- -*- C -*-

# GradeForthQuiz.pl
# By Kevin McFadden (kevin@sherman.pas.rochester.edu) May 1995

# This perl cgi script serves two purposes: to learn cgi programming
# in perl and to grade my Introduction To FORTH Quiz
# (URL:http://sherman.pas.rochester.edu/~kevin/Dspsys/forth.html).

# This script also demonstrates how to handle the main types of HTML-2.0
# buttons and such.

# LIST OF VARIABLES IN QUIZ.HTML

# FILL_THIS_IN

# This program uses Steve Brenner's cgi-lib.pl library to handle the
# input.

@INC=("/applic/nir/sun4/WWW/cgi-bin");
require '/applic/nir/sun4/lib/perl/cgi-lib.pl';

# Answers...

$total_questions = 23;
$total_correct = 0;

%answers = (N_Loop, "50",
            Loop_Exit, "abort", 
            Line_With_Error, "20", 
            Dup_Match, "( n1 -- n1 n1 )",
            TwoDup_Match, "( n1 n2 -- n1 n2 n1 n2 )",
            Swap_Match, "( n1 n2 -- n2 n1 )",
            Rot_Match, "( n1 n2 n3 -- n2 n3 n1 )",
            Over_Match, "( n1 n2 -- n1 n2 n1 )",
            Divide_Op, "2", 
            Mod_Op, "1", 
            Float_Div_Op, "30.0",
            TwoTimes_TwoPlus_OnePlus_Op, "23",
            Or_Op, "11", 
            And_Op, "2", 
            Not_Op, "-90",
            LT_Op, "FALSE", 
            GT_Op, "TRUE", 
            Zero_Equals_Op, "FALSE",
            FLTE_Op, "TRUE",
            x3y10, "C",
            x7y7, "A",
            x9y8, "D",
            x0y0, "B");

$Loop_Exit2 = "abort\"";        # Two valid answers...

# The script...

&ReadParse;                     # Get the user's input as an
                                # associative array, keyed by variable
                                # name. To use a form variable, just
                                # use the name (e.g. Divide_Op).

print &PrintHeader;

print "<HTML>\n";
print "<HEAD>\n";
print "<TITLE>Graded Forth Quiz</TITLE>\n";
print "</HEAD>\n";
print "<BODY>\n";

print "<A HREF=\"http://sherman.pas.rochester.edu/~kevin/Lab/Forth/forth.html\">";
print "Top: Dspsys Index <IMG SRC=\"/icons/top.gif\" ALIGN=bottom></A>\n";

print "<IMG SRC=\"/icons/blank.xbm\">";

print "<A HREF=\"http://sherman.pas.rochester.edu/~kevin/Lab/Forth/quiz.html\">";
print "Top: Quiz! <IMG SRC=\"/icons/back.gif\" ALIGN=bottom></A>\n";

print "<HR>\n";

# Calculate Grade

while (($key, $value) = each %answers)
{
#    print $key, ":    ", $in{$key}, "\t", $value, "<BR>\n";
    if ($in{$key} eq $value)
    {
#        print "correct<BR>\n";
        $total_correct++;
    }
#    else
#    {
#        print "****not correct<BR>\n";
#    }
}

$grade = $total_correct/$total_questions*100;
print "<H1>You answered $total_correct out of $total_questions for ";
print "a grade of $grade.</H1><P>\n";

# Give answers...

print "\n";
print "<H1>Here are the solutions...</H1>\n";
print "\n";

############################################################
# Question 1
############################################################
print "<HR>";
print "(1) How many times should the following loop execute?\n";
print "<PRE>     ok 50 25 5 */ 100 - 100 do get-data write-data loop</PRE>";
print "<P>\n";

if ( $in{'N_Loop'} eq $answers{'N_Loop'} )
{
    print "<H3> $in{'N_Loop'} is the correct answer!</H3><P>\n";
}
else
{
    print "<H3>$in{'N_Loop'} is incorrect.  The correct answer is ",
          "$answers{'N_Loop'}.\n";
    print "  Solution:</H3> <P>\n";

    print "<PRE>";
    print "     50 25 5 */ 100 - 100 do ... loop\n";
    print "     1250 5 / 100 - 100 do ... loop\n";
    print "     250 100 - 100 do ... loop\n";
    print "     150 100 do ... loop\n";
    print "     do loop executes from 100 up to, but not including,<BR>\n";
    print "     150, so it loops 50 times.</PRE><P>\n";
}

############################################################
# Question 2
############################################################
print "<HR>";
print "(2) Should the loop in (1) fail to execute the expected ";
print "number of times, which of the words introduced might have ";
print "caused the loop to exit early?<P>\n";

if ( ($in{'Loop_Exit'} eq $answers{'Loop_Exit'}) ||
      ($in{'Loop_Exit'} eq $Loop_Exit2) )
{
    print "<H3> $in{'Loop_Exit'} is the correct answer!</H3><P>\n";
}
else
{
    print "<H3>$in{'Loop_Exit'} is incorrect.  The correct answer is ",
          "$answers{'Loop_Exit'}.\n";
    print "  Solution:</H3> <P>\n";

    print "<PRE>\n";
    print "     Remember, <TT>abort</TT> stops all execution and clears ";
    print "the stack.\n     Another valid answer would be <TT>$Loop_Exit2</TT>.";
    print "</PRE><P>\n";
}    

############################################################
# Question 3
############################################################
print "<HR>";
print "(3) The following word will work properly except for one ";
print "mistake. Which line contains the error?<P>\n";

if ( $in{'Line_With_Error'} eq $answers{'Line_With_Error'} )
{
    print "<H3>$in{'Line_With_Error'} is the correct answer!</H3><P>\n";
}
else
{
    print "<H3>$in{'Line_With_Error'} is incorrect.  The correct answer is ";
    print "$answers{'Line_With_Error'}.\n";
    print "  Solution:</H3> <P>\n";

    print "<PRE>\n";

    print "          20     else    .\"col and row must each be less than ";
    print "10\!\" cr<P>\n";
    print "     Line $answers{'Line_With_Error'} is incorrect because ";
    print "a space was forgotten after <TT>.\"</TT>\n";
    print "     which occurs after the <TT>else</TT>.\n";
    print "</PRE><P>\n";
}

############################################################
# Question 4
############################################################
print "<HR>";
print "(4) Match the stack notation with the appropriate word.<P>\n";

print "<PRE><H3>";

if ( $in{'Dup_Match'} eq $answers{'Dup_Match'} )
{
    print "a) dup is $in{'Dup_Match'}.  You are correct!.\n";
}
else
{
    print "a) dup is not $in{'Dup_Match'}.\n     The correct answer is ";
    print "$answers{'Dup_Match'}.\n";
}

if ( $in{'TwoDup_Match'} eq $answers{'TwoDup_Match'} )
{
    print "b) 2dup is $in{'TwoDup_Match'}.  You are correct!.\n";
}
else
{
    print "b) 2dup is not $in{'TwoDup_Match'}.\n     The correct answer is ";
    print "$answers{'TwoDup_Match'}.\n";
}

if ( $in{'Swap_Match'} eq $answers{'Swap_Match'} )
{
    print "c) swap is $in{'Swap_Match'}.  You are correct! \n";
}
else
{
    print "c) swap is not $in{'Swap_Match'}.\n     The correct answer is ";
    print "$answers{'Swap_Match'}.\n";
}

if ( $in{'Rot_Match'} eq $answers{'Rot_Match'} )
{
    print "d) rot is $in{'Rot_Match'}.  You are correct!.\n";
}
else
{
    print "d) rot is not $in{'Rot_Match'}.\n     The correct answer is ";
    print "$answers{'Rot_Match'}.\n";
}

if ( $in{'Over_Match'} eq $answers{'Over_Match'} )
{
    print "e) over is $in{'Over_Match'}.  You are correct!.\n";
}
else
{
    print "e) over is not $in{'Over_Match'}.\n     The correct answer is ";
    print "$answers{'Over_Match'}.\n";
}

print "</PRE></H3>";

############################################################
# Question 5
############################################################
print "<HR>";
print "(5) What is the result of each operation below?<P>\n";

if ( $in{'Divide_Op'} eq $answers{'Divide_Op'} )
{
    print "<H3>a) \"7 3 /\" is $in{'Divide_Op'}. Correct!</H3>\n";
}
else
{
    print "<H3>a) \"7 3 /\" is not $in{'Divide_Op'}. The correct answer is ";
    print "$answers{'Divide_Op'}. Solution:</H3>\n";

    print "<PRE>";
    print "     7 / 3 = 2.33\n";
    print "           = 2 because Forth drops the fractional part.</PRE>\n";
}

if ( $in{'Mod_Op'} eq $answers{'Mod_Op'} )
{
    print "<H3>b) \"81 10 mod\" is $in{'Mod_Op'}. Correct!</H3>\n";
}
else
{
    print "<H3>b) \"81 10 mod\" is not $in{'Mod_Op'}. The correct answer is ";
    print "$answers{'Mod_Op'}. Solution:</H3>\n";

    print "<PRE>";
    print "     81 mod 10 = 8 1/10\n";
    print "               = 1 because mod returns the remainder.</PRE>\n";
}

if ( $in{'Float_Div_Op'} eq $answers{'Float_Div_Op'} )
{
    print "<H3>c) \"3.33e1 1.11e0 f/\" is $in{'Float_Div_Op'}. Correct!</H3>\n";
}
else
{
    print "<H3>c) \"3.33e1 1.11e0 f/\" is not $in{'Float_Div_Op'}. ";
    print "The correct answer is ";
    print "$answers{'Float_Div_Op'}. Solution:</H3>\n";

    print "<PRE>";
    print "     3.33e1 / 1.11e0\n";
    print "     33.3   / 1.11\n";
    print "                     = 30.0\n";
    print "\n";
    print "30 is technically correct, but the result is stored on the\n";
    print "floating point stack as 30.0\n</PRE>";
}

if ($in{'TwoTimes_TwoPlus_OnePlus_Op'} eq 
    $answers{'TwoTimes_TwoPlus_OnePlus_Op'} )
{
    print "<H3>d) \"10 2* 2+ 1+\" is $in{'TwoTimes_TwoPlus_OnePlus_Op'}. ";
    print "Correct!</H3>\n";
}
else
{
    print "<H3>d) \"10 2* 2+ 1+\" is not $in{'TwoTimes_TwoPlus_OnePlus_Op'}. ";
    print "The correct answer is ";
    print "$answers{'TwoTimes_TwoPlus_OnePlus_Op'}. Solution:</H3>\n";

    print "<PRE>";
    print "     10 * 2 + 2 + 1 = 23</PRE>\n";
}

if ( $in{'Or_Op'} eq $answers{'Or_Op'} )
{
    print "<H3>e) \"10 3 or\" is $in{'Or_Op'}. Correct!</H3>\n";
}
else
{
    print "<H3>e) \"10 3 or\" is not $in{'Or_Op'}. The correct answer is ";
    print "$answers{'Or_Op'}. Solution:</H3>\n";

    print "<PRE>";
    print "     10 or 3 = 1010 or 11 in binary.\n";
    print "             = 1011\n";
    print "             = 11 in decimal. </PRE>\n";
}

if ( $in{'And_Op'} eq $answers{'And_Op'} )
{
    print "<H3>f) \"10 3 and\" is $in{'And_Op'}. Correct!</H3>\n";
}
else
{
    print "<H3>f) \"10 3 and\" is not $in{'And_Op'}. The correct answer is ";
    print "$answers{'And_Op'}. Solution:</H3>\n";

    print "<PRE>";
    print "     10 3 and = 1010 and 0011 in binary.\n";
    print "              = 0010\n";
    print "              = 2 in decimal.</PRE>\n";
}

if ( $in{'Not_Op'} eq $answers{'Not_Op'} )
{
    print "<H3>g) \"89 not\" is $in{'Not_Op'}. Correct!</H3>\n";
}
else
{
    print "<H3>g) \"89 not\" is not $in{'Not_Op'}. The correct answer is ";
    print "$answers{'Not_Op'}. Solution:</H3>\n";

    print "<PRE>";
    print "     89 not =  -1 - 89 (The easy way to think of it.)\n";
    print "            =  -90\n";

    print "            =  1011001 not\n";
    print "            =  000000000000000000000000001011001 not\n";
    print "            =  111111111111111111111111110100110\n";
    print "               This is the computer's representation of -90\n";
    print "               because negative numbers are really just very\n";
    print "               large integers. ";
    print "Convert it to our representation of -90:\n";
    print "               Add up the zeroes and you get 89 ";
    print "(2^0+2^3+2^4+2^6).\n";
    print "               Since 111111111111111111111111111111111 is -1 ";
    print "in decimal,\n";
    print "               89 less than this is -90, or -1011010.</PRE>\n";
}

############################################################
# Question 6
############################################################
print "<HR>";
print "(6) Answer \"true\" or \"false\" for each of the following ";
print "comparisons.<P>\n";

if ( $in{'LT_Op'} eq $answers{'LT_Op'} )
{
    print "<H3>a) \"7 7 <\" is $in{'LT_Op'}. Correct!</H3>\n";
}
else
{
    print "<H3>a) \"7 7 <\" is not $in{'LT_Op'}. The correct answer is ";
    print "$answers{'LT_Op'}.</H3>\n";
}

if ( $in{'GT_Op'} eq $answers{'GT_Op'} )
{
    print "<H3>b) \"76 33 >\" is $in{'GT_Op'}. Correct!</H3>\n";
}
else
{
    print "<H3>b) \"76 33 >\" is not $in{'GT_Op'}. The correct answer is ";
    print "$answers{'GT_Op'}.</H3>\n";
}

if ( $in{'Zero_Equals_Op'} eq $answers{'Zero_Equals_Op'} )
{
    print "<H3>c) \"0 3 0=\" is $in{'Zero_Equals_Op'}. Correct!</H3>\n";
}
else
{
    print "<H3>c) \"0 3 0=\" is not $in{'Zero_Equals_Op'}. The correct answer is ";
    print "$answers{'Zero_Equals_Op'}.</H3>\n";
}

if ( $in{'FLTE_Op'} eq $answers{'FLTE_Op'} )
{
    print "<H3>d) \"3e1 5e1 f<=\" is $in{'FLTE_Op'}. Correct!</H3>\n";
}
else
{
    print "<H3>d) \"3e1 5e1 f<=\" is not $in{'FLTE_Op'}. The correct answer is ";
    print "$answers{'FLTE_Op'}.</H3>\n";
}

############################################################
# Question 7
############################################################
print "<HR>";
print "(7) For each value of x and y, which code block will be ";
print "executed? <P> \n";

print "<PRE>";
print "    : if-then-else-fun  ( x y -- )  \ Do stuff based on x and y.\n";
print "        2dup =\n";
print "        if\n";
print "            over 0&gt;\n";
print "            over 0&gt; and\n";
print "            if\n";
print "                [Code Block A]\n";
print "            else\n";
print "                [Code Block B]\n";
print "            then\n";
print "        else\n";
print "            1+ -\n";
print "            if\n";
print "                [Code Block C]\n";
print "            else\n";
print "                [Code Block D]\n";
print "            then\n";
print "        then  ;\n";
print "</PRE>";

if ( $in{'x3y10'} eq $answers{'x3y10'} )
{
    print "<H3>a) $in{'x3y10'} is the correct answer!</H3>\n";
}
else
{
    print "<H3>a) $in{'x3y10'} is incorrect. The correct answer is ";
    print "$answers{'x3y10'}. Solution:</H3>\n";

    print "<PRE>";
    print "                         ( 3 10 )\n";
    print "     2dup =              ( 3 10 0 )\n";
    print "     if                  ( 3 10 ) Go to else.\n";
    print "     1+ -                ( 7 )\n";
    print "     if                  ( )\n";
    print "     Code Block C</PRE>\n";
}

if ( $in{'x7y7'} eq $answers{'x7y7'} )
{
    print "<H3>b) $in{'x7y7'} is the correct answer!</H3>\n";
}
else
{
    print "<H3>b) $in{'x7y7'} is incorrect. The correct answer is ";
    print "$answers{'x7y7'}. Solution:</H3>\n";

    print "<PRE>";
    print "                         ( 7 7 )\n";
    print "     2dup =              ( 7 7 -1 )\n";
    print "     if                  ( 7 7 ) Continue with if.\n";
    print "     over 0>             ( 7 7 -1 )\n";
    print "     over 0>             ( 7 7 -1 -1 )\n";
    print "     and                 ( 7 7 -1 )\n";
    print "     if                  ( 7 7 )\n";
    print "     Code Block A</PRE>\n";
}

if ( $in{'x9y8'} eq $answers{'x9y8'} )
{
    print "<H3>c) $in{'x9y8'} is the correct answer!</H3>\n";
}
else
{
    print "<H3>c) $in{'x9y8'} is incorrect. The correct answer is ";
    print "$answers{'x9y8'}. Solution:</H3>\n";

    print "<PRE>";
    print "                         ( 9 8 )\n";
    print "     2dup =              ( 9 8 0 )\n";
    print "     if                  ( 9 8 ) Go to else.\n";
    print "     1+ -                ( 0 )\n";
    print "     if                  ( ) Go to else.\n";
    print "     Code Block D.</PRE>\n";
}

if ( $in{'x0y0'} eq $answers{'x0y0'} )
{
    print "<H3>d) $in{'x0y0'} is the correct answer!</H3>\n";
}
else
{
    print "<H3>d) $in{'x0y0'} is incorrect. The correct answer is ";
    print "$answers{'x0y0'}. Solution:</H3>\n";

    print "<PRE>";
    print "                         ( 0 0 )\n";
    print "     2dup =              ( 0 0 -1 )\n";
    print "     if                  ( 0 0 ) Continue with if.\n";
    print "     over 0>             ( 0 0 -1 )\n";
    print "     over 0>             ( 0 0 -1 -1 )\n";
    print "     and                 ( 0 0 0 )\n";
    print "     if                  ( 7 7 ) Go to else.\n";
    print "     Code Block B</PRE>\n";
}

print "<HR>";

print "<A HREF=\"http://sherman.pas.rochester.edu/~kevin/Lab/Forth/forth.html\">";
print "Top: Dspsys Index <IMG SRC=\"/icons/top.gif\" ALIGN=bottom></A>";

print "<IMG SRC=\"/icons/blank.xbm\">";

print "<A HREF=\"http://sherman.pas.rochester.edu/~kevin/Lab/Forth/quiz.html\">";
print "Top: Quiz! <IMG SRC=\"/icons/back.gif\" ALIGN=bottom></A>\n";

print "</BODY>\n";
print "</HTML>\n";
