C:\Users\brock\Documents\CSCI 255\NetBeans\RL Assign\RLexec.c
/* This file contains sections for modification */

/*
 * Routines for "intrepetting" an RL program and listing its variable.
 *
 * Copyright J. Dean Brock, 2010
 * This file released under terms of the GNU General Public License
 *
 */

#include "RLexec.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
/* Following include for sanity check */
#include <ctype.h>

/* This can be removed from the final version */
static int SanityCheck(struct RLAssignmentNode *p ) ;

/* Even though you don't modify this routine, you should study it */
RLVariableTable interpretRL(struct RLAssignmentNode *program) {
    RLVariableTable t ;
    /* This line can be removed when program is running */
    if (!SanityCheck(program)) return (RLVariableTable) NULL ;
    t = RLVTcreate() ;
    /* Iterate through the assignments of the program */
    while (program != (struct RLAssignmentNode *)NULL) {
        double arg1D, arg2D, result ;
        struct RLVariableNode *argV ;
        char *argS ;

        /* Process the first operand */
        if (program->value.op1Type == oprndVar) {
            argS = program->value.arg1.VarName ;
            argV = RLVTlookup(t, argS) ;
            if (argV == NULL)
                arg1D = 0.0 ;          /* Fail silently */
            else
                arg1D = argV->value ;
        } else
            arg1D = program->value.arg1.ConstValue ;

        /* process the 2nd operand */
        if (program->value.op2Type == oprndVar) {
            argS = program->value.arg2.VarName ;
            argV = RLVTlookup(t, argS) ;
            if (argV == NULL)
                arg2D = 0.0 ;          /* Fail silently */
            else
                arg2D = argV->value ;
        } else
            arg2D = program->value.arg2.ConstValue ;

        /* Determine the result */
        if (program->value.operator == optorSer)
            result = arg1D + arg2D ;
        else if (arg1D == 0.0 || arg2D == 0.0)
            result = 0.0 ;
        else
            result = 1/(1/arg1D + 1/arg2D) ;

        /* Insert variable with result */
        argV = RLVTinsert(t, program) ;
        argV->value = result ;

        program = program->next ;
    }
    return t ;
}

void listByNameRL(RLVariableTable t, FILE *f) {
    int i ;
    struct RLVariableNode *dummyNode, *printNode ;
    if (t == NULL) return ;
    /* RL Modification C:
     *
     * List the RL variables in alphabetical order.
     *
     * This requires a doubly-nested for-loop.
     * The outer loop is a for that passes through the 26 header nodes.
     * (Don't print the actual header nodes.  They contain no data.)
     * The inner loop passes through the nodes on each of the
     * chains.
     *
     * This original code contined 10 lines, but three of them
     * were the following fprintf which you should uncomment
     *
            fprintf(f, "%" RLVARF ": %" RLCONSTF "\n" ,
                    printNode->variable->value.Target,
                    printNode->value) ;
     *
     */
    fputc('\n', f) ;
}

static int cmpVarValue(const void * V1, const void * V2) ;

void listByValueRL(RLVariableTable t, FILE *f) {
    struct RLVariableNode **sortedMess, *dummyNode, *presNode ;
    int i, psm ;
    if (t == NULL) return ;
    /* Allocate an array sortedMess big enough to contains pointers
     * to all of the RL variable nodes.  Because these pointers are
     * of type struct RLVariableNode *; sortedMess, a pointer to
     * pointers is of type struct RLVariableNode **
     */
    sortedMess = (struct RLVariableNode **)
                      calloc(t->numberItems, sizeof *sortedMess) ;
    psm = 0 ;        /* will index elements of sortedMess */

    /* RL Modification D -- part 1:
     *
     * Write a doubly nested loop with some resemblence to the
     * one in listByNameRL (Modification C).  However, this time
     * fill sortedMess with pointers to *all* the variable nodes.
     *
     * 9 lines of code were removed here.
     */


    /* Call qsort on sortedMess and then print the results */
    qsort((void *)sortedMess,
          t->numberItems,
          sizeof(struct RLVariableNode *),
          &cmpVarValue) ;
    for (psm=0; psm<t->numberItems; ++psm) {
        fprintf(f, "%" RLVARF ": %" RLCONSTF "\n" ,
                sortedMess[psm]->variable->value.Target,
                sortedMess[psm]->value) ;
    }
    free(sortedMess) ;
}

/* The compar function for qsort. (Similar to Java's comparable interface.) */
static int cmpVarValue(const void * V1, const void * V2) {
    /* Every qsort compar starts with some horrific casts */
    struct RLVariableNode *Var1 = *(struct RLVariableNode **)V1 ;
    struct RLVariableNode *Var2 = *(struct RLVariableNode **)V2 ;

    /* RL Modification D -- part 2:
     *
     * Var1 and Var2 point to two differenct variable nodes.
     * Write a section of code that returns:
     *   -1 -- if the value of Var1 is less than Var2
     *    1 -- if the value of Var1 is greater than Var2
     * Should the values of the two variables be the same
     * "break" the tie comparing the names of the variables
     * using strncmp.
     *
     * 9 lines of code were removed here.
     */
}


/* This can be removed from the final version .
 * It is a hack to guess if modification A of
 * RLparse.c has been completed.
 */
static int SanityCheck(struct RLAssignmentNode *p ) {
    struct RLAssignment *a = &p->value ;      /* Trick to shorten the tests */
    return (isalpha(a->Target[0])
            && (a->operator == optorSer || a->operator == optorPar)
            && (a->op1Type == oprndVar || a->op1Type == oprndConst)
            && (a->op2Type == oprndVar || a->op2Type == oprndConst)
            && (isalpha(a->arg1.VarName[0]) || a->arg1.ConstValue >= 0.0)
            && (isalpha(a->arg2.VarName[0]) || a->arg2.ConstValue >= 0.0)) ;
}