1 //  Expression reading routines for runoff.
  2 //  Last modified on 05/30/74 at 18:45:50 by R F Mabee.
  3 //
  4 //  Routines defined in this module:
  5 //        ReadNumber          Scan and evaluate numeric field of control line.
  6 //        MakeN               Convert string to number (character constant).
  7 //        ReadExp             Scan and evaluate arbitrary expression in control line.
  8 //        Skip                Advance pointer to next non-blank.
  9 //        ReadParam           Evaluate expression setting or adding to old value.
 10 //        ReadString          Scan string constant.
 11 //        GetString           Read string and store in free storage vector.
 12 //        SubscriptString     Evaluate substring expression.
 13 //  Only ReadNumber, ReadExp, ReadParam, ReadString, and GetString are external.
 14 
 15 //  Copyright (c) 1974 by Massachusetts Institute of Technology and Honeywell Information Systems, Inc.
 16 
 17 //  General permission is granted to copy and use this program, but not to sell it, provided that the above
 18 //  copyright statement is given.  Contact Information Processing Services, MIT, for further information.
 19 //  Please contact R F Mabee at MIT for information on this program and versions for other machines.
 20 
 21 get "head"
 22 get "runoff_head"
 23 
 24 
 25 let ReadNumber (b) = valof              //  Read and evaluate a number, base b.
 26      $(   let n = 0
 27           while 0 le Rawchar!Nrx - '0' < b & Nrx < Nr do    //  For all digits.
 28                $(   n := n * b + Rawchar!Nrx - '0'          //  Add in digit.
 29                     Nrx := Nrx + 1
 30                $)
 31           while Rawchar!Nrx = '*s' & Nrx < Nr do Nrx := Nrx + 1       //  Skip over following white space.
 32           resultis n
 33      $)
 34 and MakeN (v) = valof                   //  Convert string to character (number).
 35      $(   let x = 0
 36           for i = 1 to Length (v) do x := x lshift ByteBits logor Subch (v, i)
 37           resultis x
 38      $)
 39 
 40 let ReadExp (n, v) = valof              //  Read and evaluate a subexpression of precedence n.
 41                                         //  v is work space for strings.
 42      $(   if Nrx ge Nr do
 43                $(   ExpError := true    //  Null expression is error.
 44                     resultis 0
 45                $)
 46           let String = false
 47           let A = valof switchon Rawchar!Nrx into           //  Get primary expression.
 48                $(   case '^': Skip ()
 49                               resultis ^ ReadExp (3, v)
 50                     case '-': Skip ()
 51                               resultis - ReadExp (5, v)
 52                     case '(': Skip ()
 53                               A := ReadExp (0, v)
 54                               test Rawchar!Nrx = ')'
 55                               then Skip ()
 56                               or ExpError := true
 57                               resultis A
 58                     case '0': case '1': case '2': case '3': case '4':
 59                     case '5': case '6': case '7': case '8': case '9':
 60                               resultis ReadNumber (10)
 61                     case '#': Skip ()
 62                               resultis ReadNumber (8)
 63                     case '"': String := true
 64                               ReadString (v)
 65                               resultis MakeN (v)
 66 
 67                     default:  ExpError := true              //  Unrecognizable character, must be error.
 68                               resultis 0
 69                $)
 70 
 71           while Nrx < Nr do             //  Read possible multiple operators at this precedence.
 72                $(   let Op = Rawchar!Nrx
 73                     let NewNrx = Nrx
 74                     if Rawchar!(Nrx + 1) = '*b' do
 75                          $(   Op := (Op lshift ByteBits logor '*b') lshift ByteBits logor Rawchar!(Nrx + 2)
 76                               NewNrx := NewNrx + 2
 77                          $)
 78 
 79                     let p = valof switchon Op into          //  Get precedence of current operator.
 80                          $(   case '=^H_':
 81                               case '|': resultis 2
 82                               case '&': resultis 3
 83                               case '=': case '<': case '>':
 84                               case '/^H=': case '<^H_': case '>^H_':
 85                                         resultis 4
 86                               case '+': case '-':
 87                                         resultis 5
 88                               case '**': case '/': case '\':
 89                                         resultis 6
 90                               case '#': unless String break
 91                                         A := Length (v)
 92                                         Nrx := NewNrx
 93                                         Skip ()
 94                                         String := false
 95                                         loop
 96                               default:  break               //  Not a known operator, end of expression.
 97                          $)
 98                     if p le n break               //  Operator less binding, return.
 99 
100                     Nrx := NewNrx
101                     Skip ()                       //  Over operator.
102                     let B = 0
103                     test String & Rawchar!Nrx = '"' & p = 4           //  Check for string comparison.
104                     then $(   let w = vec Maxline
105                               ReadString (w)
106                               A := CompareStrings (v, w)
107                          $)
108                     or B := ReadExp (p, v)
109                     String := false
110 
111                     A := valof switchon Op into             //  Apply the operator.
112                          $(   case '|': resultis A | B
113                               case '=^H_':        resultis A eqv B
114                               case '&': resultis A & B
115                               case '=': resultis A = B
116                               case '<': resultis A < B
117                               case '>': resultis A > B
118                               case '/^H=':        resultis A ne B
119                               case '<^H_':        resultis A le B
120                               case '>^H_':        resultis A ge B
121                               case '+': resultis A + B
122                               case '-': resultis A - B
123                               case '**':resultis A * B
124                               case '/': resultis B = 0 -> 0,  A / B
125                               case '\': resultis B = 0 -> 0,  A rem B
126                          $)
127                $)                       //  Repeat until done.
128 
129           resultis A
130      $)
131 and Skip () be                //  Skip over current character and following blank space.
132           Nrx := Nrx + 1 repeatwhile Rawchar!Nrx = '*s' & Nrx < Nr
133 and ReadParam (P) = valof     //  Read parameter where leading + or - means add or subtract from current value.
134      $(   ExpError := false
135           let v = vec Maxline
136 
137           test Rawchar!Nrx = '+'        //  Adding.
138           then $(   Skip ()
139                     P := P + ReadExp (4, v)
140                $)
141           or test Rawchar!Nrx = '-'     //  Subtracting.
142           then $(   Skip ()
143                     P := P - ReadExp (4, v)
144                $)
145           or P := ReadExp (0, v)        //  Or just setting.
146           if ExpError | Nrx < Nr do Report ("Malformed expression")
147           resultis P
148      $)
149 and ReadString (w) be                   //  Read string expression into vector.
150      $(   let i, v = 0, vec Maxline
151                $(   Nrx := Nrx + 1
152                     let c = Rawchar!Nrx
153                     test c = '**'                 //  Escape convention.
154                     then $(   Nrx := Nrx + 1
155                               c := valof switchon Rawchar!Nrx into
156                                    $(   case 'n': resultis '*n'
157                                         case 't': resultis '*t'
158                                         case 's': resultis '*s'
159                                         case 'b': resultis '*b'
160                                         case 'c': c := 0
161                                                   for i = 1 to 3 do
162                                                        $(   unless '0' le Rawchar!(Nrx + 1) le '9' break
163                                                             Nrx := Nrx + 1
164                                                             c := c * 10 + Rawchar!Nrx - '0'
165                                                        $)
166                                                   resultis c & $8177
167                                         default:  resultis Rawchar!Nrx
168                                    $)
169                          $)
170                     or if c = '"' do              //  End of string.
171                          $(   Skip ()
172                               while Nrx < Nr & Rawchar!Nrx = '(' do i := SubscriptString (v, i)
173                               if Nrx < Nr & Rawchar!Nrx = '"' loop
174                               break
175                          $)
176                     i := i + 1
177                     v!i := c
178                $)   repeatwhile Nrx < Nr                    //  Gather characters of string until end of line.
179 
180           v!0 := i
181           Packstring (v, w)
182      $)
183 and GetString () = valof      //  Read string and store in new vector.
184      $(   let v = vec Maxline
185           ExpError := false
186           ReadString (v)
187           if ExpError | Nrx < Nr do Report ("Malformed string expression")
188           resultis StoreString (v)
189      $)
190 and SubscriptString (v, i) = valof                //  Take substring, read subscript expression.
191      $(   Skip ()
192           let w = vec Maxline
193           let a = MinI (ReadExp (4, w), i + 1)    //  Character index for beginning of substring.
194           if a < 0 do a := a + i + 1              //  Negative first indicates offset from end.
195           if a le 0 do a := 1
196           let b = i - a + 1
197           if Rawchar!Nrx = ',' do
198                $(   Skip ()                       //  Second operand, length of substring.
199                     b := MinI (ReadExp (4, w), b)
200                     if b < 0 do b := MaxI (b + i - a + 2, 0)
201                $)
202           if Rawchar!Nrx ne ')' do
203                $(   ExpError := true
204                     resultis i
205                $)
206           for i = 1 to b do v!i := v!(a + i - 1)            //  Take the indicated substring.
207           Skip ()
208           resultis b
209      $)