      PROGRAM ACADEM
************************************************************************
* Program to determine academic standing of engineering students       *
* according to two criteria:  cumulative hours and cumulative gpa.     *
* It also counts the total # of students checked and the # found to   *
* be in good standing, and calculates the average current gpa for all   *
* students.  Variables used are:                                       *
*     NUMSTU : total number of students                                *
*     NUMGS  : number in good standing                                 *
*     RESPON : user response to more-data inquiry                      *
*     GPASUM : sum of all current GPAs                                 *
*                                                                      *
* Input:  RESPON; also several items of student information in         *
*         subroutine CALCUL                                            *
* Output: Student report by subroutine REPORT and summary statistics   *
*         by subroutine WRAPUP                                         *
************************************************************************

      INTEGER NUMSTU, NUMGS
      CHARACTER*1 RESPON
      REAL GPASUM
      DATA NUMSTU, NUMGS, GPASUM /3*0/

      CALL INFORM

*     Repeat the following until no more data
 10   CONTINUE
         CALL PROCES(NUMSTU, NUMGS, GPASUM)
         PRINT *
         PRINT *, 'MORE (Y OR N)?'
         READ '(A)', RESPON
      IF (RESPON .EQ. 'Y') GO TO 10

      CALL WRAPUP(NUMSTU, NUMGS, GPASUM)

      END 


** INFORM *************************************************************
*  Subroutine to display instructions to the user.                    *
*  Output:  Several lines of instructions                             *
***********************************************************************

      SUBROUTINE INFORM

      PRINT *, 'YOU WILL FIRST BE ASKED TO ENTER THE STUDENT''S'
      PRINT *, 'NUMBER, CLASS, CUMULATIVE HOURS, AND CUMULATIVE GPA.'
      PRINT *, 'ENTER THESE WITH AT LEAST ONE SPACE OR COMMA',
     +         ' SEPARATING THEM.'
      PRINT *
      PRINT *, 'YOU WILL THEN BE ASKED TO ENTER THE NUMBER OF HOURS AND'
      PRINT *, 'THE NUMERIC GRADE EARNED FOR EACH OF THE COURSES THE'
      PRINT *, 'STUDENT TOOK DURING THE CURRENT YEAR.  SEPARATE THE'
      PRINT *, 'NUMBER OF HOURS FROM THE GRADE BY AT LEAST ONE SPACE'
      PRINT *, 'OR BY A COMMA.  ENTER 0 FOR HOURS AND 0 FOR GRADES WHEN'
      PRINT *, 'YOU ARE FINISHED ENTERING THE INFORMATION FOR EACH',
     +          ' STUDENT.'
      PRINT *
      PRINT *
      PRINT *
      END



** PROCES **************************************************************
* Accepts student information, determines academic standing, and       *
* maintains counts of # processed and # in good standing, and a sum    *
* of current GPAs.  Variables used are:                                *
*     NUMSTU : total number of students                                *
*     NUMGS  : number in good standing                                 *
*     GPASUM : sum of all current GPAs                                 *
*     SNUMB  : student's number                                        *
*     CLASS  : student's class                                         *
*     CUMHRS : student's cumulative hours                              *
*     CUMGPA : student's cumulative GPA                                *
*     CURGPA : student's current GPA                                   *
*     GOODST : indicates whether student is in good standing           *
* Accepts:  NUMSTU, NUMGS, and GPASUM                                  *
* Returns:  Updated values of NUMSTU, NUMGS, and GPASUM                *
************************************************************************

      SUBROUTINE PROCES(NUMSTU, NUMGS, GPASUM)

      INTEGER NUMSTU, NUMGS, SNUMB, CLASS
      REAL GPASUM, CUMHRS, CUMGPA, CURGPA
      LOGICAL GOODST

      CALL CALCUL(SNUMB, CLASS, NUMSTU, CUMHRS, CUMGPA, CURGPA, 
     +            GPASUM)
      CALL CHECK(CLASS, CUMHRS, CUMGPA, GOODST, NUMGS)
      CALL REPORT(SNUMB, CLASS, CUMHRS, CURGPA, CUMGPA, GOODST)

      END


** WRAPUP *************************************************************
* Subroutine to print some summary statistics.                        *
* Accepts:  Number of students (NUMSTU), number in good standing      *
*           (NUMGS), and sum of all GPAs (GPASUM)                     *
* Output:   Report containing values of NUMSTU, NUMGA, and average    *
*           GPA                                                       *
***********************************************************************  

      SUBROUTINE WRAPUP(NUMSTU, NUMGS, GPASUM)

      INTEGER NUMSTU, NUMGS
      REAL GPASUM

      PRINT *
      PRINT *
      PRINT *, '******************************************************'
      PRINT *, '*                SUMMARY STATISTICS                  *'
      PRINT *, '******************************************************'
      PRINT *
      PRINT 10, 'NUMBER OF STUDENTS PROCESSED:   ', NUMSTU
      IF (NUMSTU .NE. 0) THEN
         PRINT 20, 'AVERAGE CURRENT GPA OF STUDENTS:',
     +             GPASUM/REAL(NUMSTU)

         PRINT 10, 'NUMBER IN GOOD STANDING:        ', NUMGS
 10      FORMAT (1X, A, I5)
 20      FORMAT (1X, A, F5.2)
      END IF

      END



** CALCUL **************************************************************
* Subroutine to read a student's number (SNUMB), CLASS, cumulative     *
* hours (CUMHRS), and cumulative gpa (CUMGPA); then read HOURS and     *
* GRADE for courses taken during the current year, and calculate       *
* current GPA (CURGPA), update cumulative hours cumulative GPA, and    *
* count (NUMSTU) of students processed.  HOURS = 0 and GRADE = 0 are   *
* used to signal the end of data for a student.  Other local variables *
* used are:                                                            *
*     NEWHRS : total hours earned during current year                  *
*     NEWPTS : honor points earned in current year                     *
*     OLDPTS : honor points earned in past years                       *
* Accepts:  NUMSTU and GPASUM                                          *
* Input:    SNUMB, CLASS, CUMHRS, CUMGPA; also HOURS and GRADE for     *
*           each of several courses                                    *
* Returns:  SNUMB, CLASS, CUMHRS, CUMGPA, CURGPA and updated values of *
*           NUMSTU and GPASUM                                          *
************************************************************************

      SUBROUTINE CALCUL(SNUMB, CLASS, NUMSTU, CUMHRS, CUMGPA, 
     +                  CURGPA, GPASUM)

      INTEGER SNUMB, NUMSTU, CLASS
      REAL CUMHRS, CUMGPA, CURGPA, GPASUM, HOURS, GRADE, NEWHRS, 
     +     NEWPTS, OLDPTS


      PRINT *,'ENTER STUDENT NUMBER, CLASS, CUM. HOURS, CUM. GPA:'
      READ *, SNUMB, CLASS, CUMHRS, CUMGPA
      OLDPTS = CUMHRS * CUMGPA
      NEWHRS = 0.0
      NEWPTS = 0.0
      PRINT *, 'HOURS AND GRADE?'
      READ *, HOURS, GRADE

* While HOURS > 0.0 do the following
 10   IF (HOURS .GT. 0.0) THEN
         NEWHRS = NEWHRS + HOURS
         NEWPTS = NEWPTS + HOURS * GRADE
         PRINT *, 'HOURS AND GRADE?'
         READ *, HOURS, GRADE
      GO TO 10
      END IF

      IF (NEWHRS .EQ. 0.0) THEN
         CURGPA = 0.0
      ELSE
         CURGPA = NEWPTS / NEWHRS
      END IF
      GPASUM = GPASUM + CURGPA
      CUMHRS = CUMHRS + NEWHRS
      CUMGPA = (OLDPTS + NEWPTS) / CUMHRS
      NUMSTU = NUMSTU + 1

      END


** CHECK ***************************************************************
* Subroutine to check academic standing.  Two criteria are used:       *
* cumulative hours and cumulative GPA.  Functions HRSCHK and GPACHK    *
* are used to check these.  CLASS, CUMHRS, and CUMGPA are the class,   *
* cumulative hours, and cumulative GPA for the student being checked.  *
* GOODST is true or false according to whether or not the student is   *
* found to be in good standing, and NUMGS is the count of students who *
* are in good standing.                                                *
* Accepts:  CLASS, CUMHRS, CUMGPA, and NUMGS                           *
* Returns:  GOODST and updated value of NUMGS                          *
* Output:   Message indicating an illegal class code                   *
************************************************************************

      SUBROUTINE CHECK(CLASS, CUMHRS, CUMGPA, GOODST, NUMGS)

      INTEGER CLASS, NUMGS
      REAL CUMHRS, CUMGPA
      LOGICAL GOODST, HRSCHK, GPACHK

      IF ((CLASS .LT. 1) .OR. (CLASS .GT. 3)) THEN
         PRINT *, '*** ILLEGAL CLASS CODE ***'
         GOODST = .FALSE.
      ELSE
         GOODST = HRSCHK(CLASS, CUMHRS) .AND. GPACHK(CLASS, CUMGPA)
      END IF
      IF (GOODST) THEN
         NUMGS = NUMGS + 1
      END IF

      END


**REPORT***************************************************************
* Subroutine to display the statistics for a given student.           *
* Accepts:  Student's number (SNUMB), CLASS, cumulative hours (CUMHRS)*
*           current GPA (CURGPA), cumulative GPA (CUMGPA), and        *
*           indicator (GOODST) whether student is in good standing    *
* Output:   SNUMB, CLASS, CUMHRS, CURGPA, and a message indicating    *
*           whether student is in good standing                       *
***********************************************************************

      SUBROUTINE REPORT(SNUMB, CLASS, CUMHRS, CURGPA, CUMGPA, GOODST)

      INTEGER SNUMB, CLASS
      REAL CUMHRS, CURGPA, CUMGPA
      LOGICAL GOODST

      PRINT *
      PRINT 10, SNUMB
 10       FORMAT (1X, '***** REPORT FOR STUDENT', I6, ' *****')
      PRINT 20, 'CLASS:           ', CLASS
 20       FORMAT(1X, A, I6)
      PRINT 30, 'CUMULATIVE HOURS:', CUMHRS
      PRINT 30, 'CURRENT GPA:     ', CURGPA
      PRINT 30, 'CUMULATIVE  GPA: ', CUMGPA
 30       FORMAT(1X, A, F6.2)
      IF (GOODST) THEN
         PRINT 40, 'IN GOOD STANDING'
      ELSE
         PRINT 40, '*** NOT IN GOOD STANDING ***'
      END IF
 40       FORMAT(1X, A / 1X, 35('*'))
      END


** HRSCHK *************************************************************
* Check cumulative hours (CUMHRS) of student in CLASS.  Local         *
* parameters FRESH, SOPH, and JUNIOR give the minimum number of hours *
* required of freshmen, sophomores, and juniors, respectively.        *
* Accepts: CLASS and CUMHRS                                           *
* Returns: True or false according to whether student has accumulated *
*          enough hours                                               *
***********************************************************************

      LOGICAL FUNCTION HRSCHK(CLASS, CUMHRS)

      INTEGER CLASS
      REAL CUMHRS, FRESH, SOPH, JUNIOR
      PARAMETER (FRESH = 25.0, SOPH = 50.0, JUNIOR = 85.0)

      IF (CLASS .EQ. 1) THEN
         HRSCHK = (CUMHRS .GE. FRESH)
      ELSE IF (CLASS .EQ. 2) THEN
         HRSCHK = (CUMHRS .GE. SOPH)
      ELSE
         HRSCHK = (CUMHRS .GE. JUNIOR)
      END IF

      END


** GPACHK *************************************************************
* Check cumulative GPA (CUMGPA) of student in CLASS. Local parameters *
* GPA1, GPA2, and GPA3 give the minimum GPA required of freshmen,     *
* sophomores, and juniors, respectively.                              *
* Accepts: CLASS and CUMGPA                                           *
* Returns: True or false according to whether student's GPA is high   *
*          enough                                                     *
***********************************************************************

      LOGICAL FUNCTION GPACHK(CLASS, CUMGPA)

      INTEGER CLASS
      REAL CUMGPA, GPA1, GPA2, GPA3
      PARAMETER (GPA1 = 1.7, GPA2 = 1.85, GPA3 = 1.95)

      IF (CLASS .EQ. 1) THEN
         GPACHK = (CUMGPA .GE. GPA1)
      ELSE IF (CLASS .EQ. 2) THEN
         GPACHK = (CUMGPA .GE. GPA2)
      ELSE
         GPACHK = (CUMGPA .GE. GPA3)
      END IF

      END
