# getsym --- get next symbol from input stream

   subroutine getsym

   include "rp_com.i"

   integer radix, i
   integer index, ctoi, ltoc
   longint val
   character c, quote
   character mapdn

   integer anyupper
   integer lookup, scopy

   untyped info (SYMINFOSIZE)

   procedure skip_blanks_and_comments forward

   repeat {    # until a symbol is found
      Symlen = 0
      Symtext (1) = EOS

      ngetch (c)
      skip_blanks_and_comments

      select (c)
      when (SET_OF_LETTERS, '$'c) {

         anyupper = NO

         repeat {
            select
               when (IS_LOWER (c) || IS_DIGIT (c) || c == '$'c) {
                  Symlen += 1
                  Symtext (Symlen) = c
                  }
               when (IS_UPPER (c)) {
                  Symlen += 1
                  Symtext (Symlen) = c
                  anyupper = YES
                  }
               when (c == '_'c)
                  ;
            else
               break
            ngetch (c)
            }
         call putback (c)
         Symtext (Symlen + 1) = EOS

         if (ARG_PRESENT (m)) {
            anyupper = NO
            call mapstr (Symtext, LOWER)
            }

         Sym_long_text (1) = EOS     # conspiracy so that all id's don't
                                     # have to be saved to access long name

         for (i = Scope_sp; i > 0; i -= 1) {
            if (Scope_table (i) ~= 0
              && lookup (Symtext, info, Scope_table (i)) == YES) {
               call scopy (Symtext, 1, Sym_long_text, 1)
               Symlen = scopy (Mem, info (SYMBOLDATA), Symtext, 1)
               Symbol = IDSYM
               break 2
               }
            }

         if (Proc_table ~= 0
           && lookup (Symtext, info, Proc_table) == YES) {
            Proc_head = info (SYMBOLDATA)
            Symbol = PROCIDSYM
            break
            }

         if (lookup (Symtext, info, Idtable) == NO) {
            if ((Symlen > MAXIDLENGTH
                     || anyupper == YES
                     || (Symtext (MAXIDLENGTH) == UFCHAR
                           && Symlen == MAXIDLENGTH))
                  && (~ ARG_PRESENT (b))) {
               call scopy (Symtext, 1, Sym_long_text, 1)
               call enter_long_name       # must be uniqued
               }
            Symbol = IDSYM
            break
            }

         select (info (SYMBOLTYPE))
         when (KEYWD_SYMBOLTYPE) {  # Ratfor or Fortran Keywords:
            Symbol = info (SYMBOLVAL)
            break
            }
         when (LNAME_SYMBOLTYPE) {  # Long Names:
            call scopy (Symtext, 1, Sym_long_text, 1)
            Symlen = scopy (Mem, info (SYMBOLDATA), Symtext, 1)
            Symbol = IDSYM
            break
            }
         when (DEFID_SYMBOLTYPE) {  # Defined Identifiers:
            call invoke_macro (info)
            next  # go back for next real symbol
            }
         else
            FATAL ("in getsym/id:  can't happen (bad symtype)"p)

         }  # end of identifier processing

      when (SET_OF_DIGITS) {                       # Integer

         while (IS_DIGIT (c)) {
            Symtext (Symlen + 1) = c   # Strange order for efficiency
            Symlen += 1
            ngetch (c)
            }
         Symtext (Symlen + 1) = EOS
         if (c == 'r'c) {        # radix specified
            i = 1
            radix = ctoi (Symtext, i)
            if (radix < 2 | radix > 16) {
               SYNERR ("Radix must be between 2 and 16"p)
               radix = 16
               }
            val = 0
            repeat {
               ngetch (c)
               if ('0'c <= c && c <= '9'c)
                  i = c - '0'c
               else
                  i = index ("0123456789abcdef"s, mapdn (c)) - 1
               if (i < 0 || i >= radix)
                  break
               val = val * radix + i
               }
            Symlen = ltoc (val, Symtext, MAXTOK)
            }
         call putback (c)

         Symbol = NUMBERSYM
         break

         }  # end of integer processing

      when ('"'c, "'"c) {                       # quoted strings
         Symbol = STRCONSTANTSYM    # may be changed within
         repeat {                   #      convert_string_constant
            quote = c
            repeat {
               ngetch (c)
               if (c == quote)
                  break
               Symlen += 1
               if (Symlen >= MAXTOK) {
                  SYNERR ("Quoted literal too long"p)
                  break 2
                  }
               Symtext (Symlen) = c
               if (c == NEWLINE) {
                  SYNERR ("Unmatched quote"p)
                  break
                  }
               }
            Symtext (Symlen + 1) = EOS
            ngetch (c)
            skip_blanks_and_comments
            } until (c ~= '"'c && c ~= "'"c)
         if ('a'c <= c && c <= 'z'c)
            call convert_string_constant (c)
         else
            call putback (c)
         break
         }

      when ('&'c) {              # .and. 'andif' and '&='
         ngetch (c)
         if (c == '&'c)
            Symbol = ANDIFSYM
         else if (c == '='c)
            Symbol = ANDABSYM
         else {
            call putback (c)
            Symlen = scopy (".AND."s, 1, Symtext, 1)
            Symbol = '&'c
            }
         break
         }

      when ('|'c) {              # .or. 'orif' and '|='
         ngetch (c)
         if (c == '|'c)
            Symbol = ORIFSYM
         else if (c == '='c)
            Symbol = ORABSYM
         else {
            call putback (c)
            Symlen = scopy (".OR."s, 1, Symtext, 1)
            Symbol = '|'c
            }
         break
         }

      when ('='c) {              # = and .eq.
         ngetch (c)
         if (c == '='c) {
            Symlen = scopy (".EQ."s, 1, Symtext, 1)
            Symbol = EQSYM
            }
         else {
            call putback (c)
            Symtext (1) = '='c
            Symtext (2) = EOS
            Symlen = 1
            Symbol = '='c
            }
         break
         }

      when ('<'c) {              # .lt. and .le.
         ngetch (c)
         if (c == '='c) {
            Symbol = LESYM
            Symlen = scopy (".LE."s, 1, Symtext, 1)
            }
         else {
            call putback (c)
            Symlen = scopy (".LT."s, 1, Symtext, 1)
            Symbol = LTSYM
            }
         break
         }

      when ('>'c) {              # .gt. and .ge.
         ngetch (c)
         if (c == '='c) {
            Symbol = GESYM
            Symlen = scopy (".GE."s, 1, Symtext, 1)
            }
         else {
            Symbol = GTSYM
            Symlen = scopy (".GT."s, 1, Symtext, 1)
            call putback (c)
            }
         break
         }

      when ('~'c) {              # .not. and .ne.
         ngetch (c)
         if (c == '='c) {
            Symbol = NESYM
            Symlen = scopy (".NE."s, 1, Symtext, 1)
            }
         else {
            Symbol = NOTSYM
            Symlen = scopy (".NOT."s, 1, Symtext, 1)
            call putback (c)
            }
         break
         }

      when ('+'c, '-'c, '*'c, '/'c, '%'c, '^'c) {
         Symbol = c
         ngetch (c)
         if (c ~= '='c) {
            Symtext (1) = Symbol
            Symtext (2) = EOS
            Symlen = 1
            call putback (c)
            }
         else
            select (Symbol)
               when ('+'c)
                  Symbol = PLUSABSYM
               when ('-'c)
                  Symbol = MINUSABSYM
               when ('*'c)
                  Symbol = TIMESABSYM
               when ('/'c)
                  Symbol = DIVABSYM
               when ('%'c)
                  Symbol = MODABSYM
               when ('^'c)
                  Symbol = XORABSYM
         break
         }

      when (','c) {
         Symbol = c
         Symtext (1) = c
         Symtext (2) = EOS
         Symlen = 1
         call putback ('_'c)   # feign continuation
         break
         }

      else {   # single_character symbol
         Symbol = c
         Symtext (1) = c
         Symtext (2) = EOS
         Symlen = 1
         break
         }

      }  # repeat until a symbol is found

DEBUG call print (ERROUT, "Symbol = *i*n"p, Symbol)
   return


   # skip_blanks_and_comments --- handle comments, continuations, skip blanks

   procedure skip_blanks_and_comments {

      repeat {
         while (c == ' 'c)
            ngetch (c)
         select (c)
         when ('_'c) {
            repeat {
               ngetch (c)
               if (c == '#'c)
                  repeat
                     ngetch (c)
                     until (c == NEWLINE)
               } until (c ~= ' 'c && c ~= NEWLINE && c ~= '_'c)
            }
          when ('#'c) {
            repeat
               ngetch (c)
               until (c == NEWLINE)
            }
         } until (c ~= ' 'c)

      }

   end



# convert_string_constant --- convert a constant to a special format

   subroutine convert_string_constant (c)
   character c

   include "rp_com.i"

   integer v, i, j
   integer itoc, scopy, tlit
   character text (MAXTOK)

   select (c)
   when ('c'c, 'C'c) {     # character constant
      if (Symlen == 1) {
         v = tlit (Symtext (1))
         Symlen = itoc (v, Symtext, MAXTOK)
         Symbol = NUMBERSYM
         }
      else
         SYNERR ("Only one character allowed in a character constant.")
      }

   when ('p'c, 'P'c) {    # period-terminated packed
      call scopy (Symtext, 1, text, 1)
      j = 0
      for (i = 1; text (i) ~= EOS; i += 1) {
         j += 1
         if (j >= MAXTOK - 1) {
            SYNERR ("Packed string constant too long"p)
            break
            }
         if (text (i) == '.'c) {
            Symtext (j) = '@'c
            j += 1
            }
         Symtext (j) = text (i)
         }
      Symtext (j + 1) = '.'c
      Symtext (j + 2) = EOS
      Symlen = j + 1
      Symbol = STRCONSTANTSYM
      }

   when ('s'c, 'S'c) {     # EOS-terminated string
      if (Outp (DATA) ~= 0 | Outp (DECL) ~= 0) {
         SYNERR ("EOS-terminated string not allowed in this context"p)
         return
         }
      call vargen (text)

      call gen_int_decl (text, Symlen + 1)

      for (i = 1; Symtext (i) ~= EOS; i += 1)
         call gen_char_data (text, i, Symtext (i))
      call gen_char_data (text, i, EOS)
      call gen_data_end

      Symlen = scopy (text, 1, Symtext, 1)
      Symbol = IDSYM
      }

   when ('v'c, 'V'c) {     # PL/I character varying
      if (Outp (DATA) ~= 0 | Outp (DECL) ~= 0) {
         SYNERR ("Varying string not allowed in this context.")
         return
         }
      call vargen (text)

      call gen_int_decl (text, (Symlen + 1) / 2 + 1)

      Symtext (Symlen + 1) = ' 'c
      call gen_data_item (text, 1, Symlen)
      for (i = 1; i <= Symlen; i += 2)
         call gen_data_item (text, i / 2 + 2,
            xor (ls (tlit (Symtext (i)), 8), tlit (Symtext (i + 1))))
      call gen_data_end

      Symlen = scopy (text, 1, Symtext, 1)
      Symbol = IDSYM
      }

   else
      SYNERR ("Unrecognizable string format indicator"p)

   return
   end



# refill_buffer --- refill the input buffer and return first character

   subroutine refill_buffer (c)
   character c

   include "rp_com.i"

   integer getlin

   repeat {
      if (Level < 1) {
         c = EOF
         Inbuf (PBLIMIT) = EOS
         Ibp = PBLIMIT
         return
         }
      if (getlin (Inbuf (PBLIMIT), Infile (Level)) ~= EOF) {
         Line_number (Level) += 1
         break
         }
      call close (Infile (Level))
      Level -= 1
      }
   c = Inbuf (PBLIMIT)
   Ibp = PBLIMIT + 1

   return
   end




# putback --- push character back onto input

   subroutine putback (c)
   character c

   include "rp_com.i"

   Ibp -= 1
   if (Ibp >= 1)
      Inbuf (Ibp) = c
   else
      FATAL ("too many characters pushed back"p)

   return
   end



# putback_str --- push string back onto input

   subroutine putback_str (str)
   character str (ARB)

   include "rp_com.i"

   integer i
   integer length

   for (i = length (str) - 1; i >= 0; i -= 1)
      call putback (str (i + 1))

   return
   end



# putback_num --- push decimal number back onto input

   subroutine putback_num (n)
   integer n

   integer len
   integer itoc

   character chars (MAXLINE)

   len = itoc (n, chars, MAXLINE)
   chars (len + 1) = EOS
   call putback_str (chars)

   return
   end



