external record (*) name Null == 0

external routine spec Proc 6 (integer {Enumeration} Enum Val Par, integer {Enumeration} name Enum Ref Par)
external routine spec Proc 7 (integer {One Fifty} Int 1 Par Val,
                                 integer {One Fifty} Int 2 Par Val,
                                 integer {One Fifty} name Int Par Ref)
external routine spec Proc 8 (integer array name Arr 1 Par Ref {(0:49)},
                                 integer array name Arr 2 Par Ref {(0:50*50-1)} {(0:49, 0:49)},
                                 integer Int 1 Par Val,
                                 integer Int 2 Par Val)
external integer {Enumeration} fn spec Func 1 (integer {Capital Letter} Ch 1 Par Val,
                                                   integer {Capital Letter} Ch 2 Par Val)
external predicate spec Func 2 (string (30) name Str 1 Par Ref, string (30) name Str 2 Par Ref)
external predicate spec Func 3 (integer {Enumeration} Enum Par Val)

! ****************************************************************************
! *
! *                   "DHRYSTONE" Benchmark Program
! *                   -----------------------------
! *                                                                            
! *  Version:    Imp, Version 2.1
! *                                                                            
! *  File:       dhry_1.c (part 2 of 3)
! *
! *  Date:       May 25, 1988 & Mar 30, 2026
! *
! *  Author:     Reinhold P. Weicker, translated from C to Imp by Graham Toal
! *
! ****************************************************************************

include "dhry.inc"

const integer DHRY ITERS = 100000

{ Global Variables: }

external record (Rec Type fm) name  Ptr Glob,
                                       Next Ptr Glob
external integer                     Int Glob
external integer {Boolean}           Bool Glob
external byte integer               Ch 1 Glob,
                                       Ch 2 Glob
external integer array              Arr 1 Glob (0:49)

!!! PROBLEM! Imp77 doesn't allow N-D external arrays, only local ones!
external integer array              Arr 2 Glob (0:50*50-1) {(0:49, 0:49)}

!extern char     *malloc ()
!!%external %integer {Enumeration} %fn %spec     Func 1
  { forward declaration necessary since Enumeration may not simply be int }

!#ifndef REG
external integer {Boolean} Reg = false
!#define REG
        { REG becomes defined as empty }
        { i.e. no register variables   }
!#else
!        %integer {Boolean} Reg = true
!#endif

{ variables for time measurement: }

!#ifdef TIMES
!struct tms      time info
!extern  int     times ()
!                { see library function "times" }
!#define Too Small Time (2*HZ)
!                { Measurements should last at least about 2 seconds }
!#endif
!#ifdef TIME
!extern long     time()
!                { see library function "time"  }
!#define Too Small Time 2
!                { Measurements should last at least 2 seconds }
!#endif
!#ifdef MSC CLOCK
!extern clock t	clock()
!#define Too Small Time (2*HZ)
!#endif

const integer           Too Small Time = 2 * 1000000  {must run at least 2 seconds}

external long integer  Begin Time, c
                          End Time, c
                          User Time
                          
external real           Microseconds, c
                          Dhrystones Per Second

{ end of variables for time measurement }


begin
{***}
  routinespec Proc 1 (record (Rec Type fm) name Ptr Val Par)
  routinespec Proc 2 (integer {One Fifty} name  Int Par Ref)
  routinespec Proc 3 (record (Rec Type fm) name Ptr Ref Par)
  routinespec Proc 4
  routinespec Proc 5

  { main program, corresponds to procedures        }
  { Main and Proc 0 in the Ada version             }
  
  integer {One Fifty}   Int 1 Loc
  integer {One Fifty}   Int 2 Loc
  integer {One Fifty}   Int 3 Loc
  byte integer         Ch Index
  integer {Enumeration} Enum Loc
  string (30)           Str 1 Loc
  string (30)           Str 2 Loc
  integer               Run Index
  integer               Number Of Runs

  { Initializations }

  record (Rec Type fm) Next Ptr Glob
  record (Rec Type fm) Ptr Glob {= (Rec Pointer) malloc (sizeof (Rec Type))}

  Ptr Glob_Ptr Comp                    == Next Ptr Glob
  Ptr Glob_Discr                       = Ident 1
  Ptr Glob_variant_var 1_Enum Comp     = Ident 3
  Ptr Glob_variant_var 1_Int Comp      = 40
  Ptr Glob_variant_var 1_Str Comp = "DHRYSTONE PROGRAM, SOME STRING"
  Str 1 Loc = "DHRYSTONE PROGRAM, 1'ST STRING"

  Arr 2 Glob (8*50+7){(8,7)} = 10
        { Was missing in published program. Without this statement,    }
        { Arr 2 Glob [8][7] would have an undefined value.             }
        { Warning: With 16-Bit processors and Number Of Runs > 32000,  }
        { overflow may occur for this array element.                   }

  newline
  printstring ("Dhrystone Benchmark, Version 2.1 (Language: Imp)")
  newlines(2)
  
  if Reg # 0 start
    printstring ("Program compiled with 'register' attribute")
    newlines(2)
  else
    printstring ("Program compiled without 'register' attribute")
    newlines(2)
  finish

  Number Of Runs = DHRY ITERS

!  printstring ("Please give the number of runs through the benchmark: ")
!  %begin
!    %integer n
!    read(n)
!    Number Of Runs = n
!  %end
!  newline

  printstring ("Execution starts, ")
  write(Number Of Runs, -1)
  printstring (" runs through Dhrystone")
  newline

  {*************}
  { Start timer }
  {*************}
 
!#ifdef TIMES
!  times (&time info)
!  Begin Time = (long) time info.tms utime
!#endif
!#ifdef TIME
!  Begin Time = time ( (long *) 0)
!#endif
!#ifdef MSC CLOCK
!  Begin Time = clock()
!#endif

  Begin Time = cpu time

  for Run Index = 1, 1, Number Of Runs cycle

    Proc 5
    Proc 4
      { Ch 1 Glob == 'A', Ch 2 Glob == 'B', Bool Glob == true }
    Int 1 Loc = 2
    Int 2 Loc = 3
    Str 2 Loc = "DHRYSTONE PROGRAM, 2'ND STRING"
    Enum Loc = Ident 2
    if not Func 2 (Str 1 Loc, Str 2 Loc) then Bool Glob = false else Bool Glob = true
      { Bool Glob == 1 }
    while Int 1 Loc < Int 2 Loc cycle { loop body executed once }
      Int 3 Loc = 5 * Int 1 Loc - Int 2 Loc
        { Int 3 Loc == 7 }
      Proc 7 (Int 1 Loc, Int 2 Loc, Int 3 Loc)
        { Int 3 Loc == 7 }
      Int 1 Loc = Int 1 Loc + 1
    repeat { while }
      { Int 1 Loc == 3, Int 2 Loc == 3, Int 3 Loc == 7 }
    Proc 8 (Arr 1 Glob, Arr 2 Glob, Int 1 Loc, Int 3 Loc)
      { Int Glob == 5 }
    Proc 1 (Ptr Glob)
    for Ch Index = 'A', 1,  Ch 2 Glob cycle
                             { loop body executed twice }
      if Enum Loc = Func 1 (Ch Index, 'C') start
          { then, not executed }
        Proc 6 (Ident 1, Enum Loc)
        Str 2 Loc = "DHRYSTONE PROGRAM, 3'RD STRING"
        Int 2 Loc = Run Index
        Int Glob = Run Index
      finish
    repeat
      { Int 1 Loc == 3, Int 2 Loc == 3, Int 3 Loc == 7 }
    Int 2 Loc = Int 2 Loc * Int 1 Loc
    Int 1 Loc = Int 2 Loc // Int 3 Loc
    Int 2 Loc = 7 * (Int 2 Loc - Int 3 Loc) - Int 1 Loc
      { Int 1 Loc == 1, Int 2 Loc == 13, Int 3 Loc == 7 }
    Proc 2 (Int 1 Loc)
      { Int 1 Loc == 5 }

  repeat { loop "for Run Index" }

  {************}
  { Stop timer }
  {************}
  
!#ifdef TIMES
!  times (&time info)
!  End Time = (long) time info.tms utime
!#endif
!#ifdef TIME
!  End Time = time ( (long *) 0)
!#endif
!#ifdef MSC CLOCK
!  End Time = clock()
!#endif

  End Time = cpu time

  printstring ("Execution ends"); newline
  printstring (""); newline
  printstring ("Final values of the variables used in the benchmark:"); newline
  printstring (""); newline
  printstring ("Int_Glob:            "); write( Int Glob, -1); newline
  printstring ("        should be:   "); write( 5, -1); newline
  printstring ("Bool_Glob:           "); write( Bool Glob, -1); newline
  printstring ("        should be:   "); write( 1, -1); newline
  printstring ("Ch_1_Glob:           "); print symbol(Ch 1 Glob); newline
  printstring ("        should be:   "); print symbol('A'); newline
  printstring ("Ch_2_Glob:           "); print symbol(Ch 2 Glob); newline
  printstring ("        should be:   "); print symbol('B'); newline
  printstring ("Arr_1_Glob[8]:       "); write( Arr 1 Glob(8), -1); newline
  printstring ("        should be:   "); write( 7, -1); newline
  printstring ("Arr_2_Glob[8][7]:    "); write( Arr 2 Glob(8*50+7){(8,7)}, -1); newline
  printstring ("        should be:   Number_Of_Runs + 10"); newline
  printstring ("Ptr_Glob->"); newline
  printstring ("  Ptr_Comp:          "); write(ADDR(Ptr Glob_Ptr Comp), -1); newline
  printstring ("        should be:   (implementation-dependent)"); newline
  printstring ("  Discr:             "); write( Ptr Glob_Discr, -1); newline
  printstring ("        should be:   "); write( 0, -1); newline
  printstring ("  Enum_Comp:         "); write( Ptr Glob_variant_var 1_Enum Comp, -1); newline
  printstring ("        should be:   "); write( 2, -1); newline
  printstring ("  Int_Comp:          "); write( Ptr Glob_variant_var 1_Int Comp, -1); newline
  printstring ("        should be:   "); write( 17, -1); newline
  printstring ("  Str_Comp:          "); print string(Ptr Glob_variant_var 1_Str Comp); newline
  printstring ("        should be:   DHRYSTONE PROGRAM, SOME STRING"); newline
  printstring ("Next_Ptr_Glob->"); newline
  printstring ("  Ptr_Comp:          "); write(ADDR(Next Ptr Glob_Ptr Comp), -1); newline
  printstring ("        should be:   (implementation-dependent), same as above"); newline
  printstring ("  Discr:             "); write( Next Ptr Glob_Discr, -1); newline
  printstring ("        should be:   "); write( 0, -1); newline
  printstring ("  Enum_Comp:         "); write( Next Ptr Glob_variant_var 1_Enum Comp, -1); newline
  printstring ("        should be:   "); write( 1, -1); newline
  printstring ("  Int_Comp:          "); write( Next Ptr Glob_variant_var 1_Int Comp, -1); newline
  printstring ("        should be:   "); write( 18, -1); newline
  printstring ("  Str_Comp:          "); print string(Next Ptr Glob_variant_var 1_Str Comp); newline
  printstring ("        should be:   DHRYSTONE PROGRAM, SOME STRING"); newline
  printstring ("Int_1_Loc:           "); write( Int 1 Loc, -1); newline
  printstring ("        should be:   "); write( 5, -1); newline
  printstring ("Int_2_Loc:           "); write( Int 2 Loc, -1); newline
  printstring ("        should be:   "); write( 13, -1); newline
  printstring ("Int_3_Loc:           "); write( Int 3 Loc, -1); newline
  printstring ("        should be:   "); write( 7, -1); newline
  printstring ("Enum_Loc:            "); write( Enum Loc, -1); newline
  printstring ("        should be:   "); write( 1, -1); newline
  printstring ("Str_1_Loc:           "); print string(Str 1 Loc); newline
  printstring ("        should be:   DHRYSTONE PROGRAM, 1'ST STRING"); newline
  printstring ("Str_2_Loc:           "); print string(Str 2 Loc); newline
  printstring ("        should be:   DHRYSTONE PROGRAM, 2'ND STRING"); newline
  newline

  User Time = End Time - Begin Time

!!  %if User Time < Too Small Time %start
!!    printf ("Measured time too small to obtain meaningful results"); newline
!!    printf ("Please increase number of runs"); newline
!!    newline
!!  %else
!#ifdef TIME
!    Microseconds = (float) User Time * Mic secs Per Second 
!                        / (float) Number Of Runs
!    Dhrystones Per Second = (float) Number Of Runs / (float) User Time
!#else
!    Microseconds = (float) User Time * Mic secs Per Second 
!                        / ((float) HZ * ((float) Number Of Runs))
!    Dhrystones Per Second = ((float) HZ * (float) Number Of Runs)
!                        / (float) User Time
!#endif

    Microseconds = User Time // Number Of Runs  {CPU TIME function has been adjusted to return microseconds!}
    Dhrystones Per Second = (Number Of Runs * (1000000//1000)) // (User Time//1000)  {need to scale down by 1000 to fit in 32-bit %integer}

    printstring ("Microseconds for one run through Dhrystone: ")
    write(INT(Microseconds), -1); space; newline
    printstring ("Dhrystones per Second:                      ")
    write(INT(Dhrystones Per Second), -1); space; newline
    newline
!!  %finish
  
!%end


routine Proc 1 (record (Rec Type fm) name Ptr Val Par)
{****************}
    { executed once }
  record (Rec Type fm) name Next Record == Ptr Val Par_Ptr Comp   {or '='???}
                                        { == Ptr Glob Next }
  { Local variable, initialized with Ptr Val Par->Ptr Comp,    }
  { corresponds to "rename" in Ada, "with" in Pascal           }
  
  {structassign} Ptr Val Par_Ptr Comp = Ptr Glob
  Ptr Val Par_variant_var 1_Int Comp = 5
  Next Record_variant_var 1_Int Comp = Ptr Val Par_variant_var 1_Int Comp
  Next Record_Ptr Comp = Ptr Val Par_Ptr Comp
  Proc 3 (Next Record_Ptr Comp)
    { Ptr Val Par_Ptr Comp_Ptr Comp = Ptr Glob_Ptr Comp }
  if Next Record_Discr = Ident 1 start
    { then, executed }
    Next Record_variant_var 1_Int Comp = 6
    Proc 6 (Ptr Val Par_variant_var 1_Enum Comp, Next Record_variant_var 1_Enum Comp)
    Next Record_Ptr Comp = Ptr Glob_Ptr Comp
    Proc 7 (Next Record_variant_var 1_Int Comp, 10, Next Record_variant_var 1_Int Comp)
  else { not executed }
    {structassign} Ptr Val Par = Ptr Val Par_Ptr Comp
  finish
end { Proc 1 }


routine Proc 2 (integer {One Fifty} name  Int Par Ref)
{****************}
    { executed once }
    { *Int Par Ref == 1, becomes 4 }
  integer {One Fifty}     Int Loc
  integer {Enumeration}   Enum Loc

  Int Loc = Int Par Ref + 10
  cycle { executed once }
    if Ch 1 Glob = 'A' start
      { then, executed }
      Int Loc = Int Loc - 1
      Int Par Ref = Int Loc - Int Glob
      Enum Loc = Ident 1
    finish { if }
  repeat until Enum Loc = Ident 1 { true }
end { Proc 2 }


routine Proc 3 (record (Rec Type fm) name Ptr Ref Par)
{****************}
    { executed once }
    { Ptr Ref Par becomes Ptr Glob }

  if Ptr Glob ## Null then { then, executed } Ptr Ref Par == Ptr Glob_Ptr Comp
  Proc 7 (10, Int Glob, Ptr Glob_variant_var 1_Int Comp)
end { Proc 3 }


routine Proc 4 { without parameters }
{*****}
    { executed once }
  integer {Boolean} Bool Loc

  if Ch 1 Glob = 'A' then Bool Loc = true else Bool Loc = false
  Bool Glob = Bool Loc ! Bool Glob
  Ch 2 Glob = 'B'
end { Proc 4 }


routine Proc 5 { without parameters }
{*****}
    { executed once }
  Ch 1 Glob = 'A'
  Bool Glob = false
end { Proc 5 }


{ Procedure for the assignment of structures,          }
{ if the C compiler doesn't support this feature       }

endofprogram