|                                                                                                              1   package gnu.kawa.lispexpr;
 2   import gnu.text.*;
 3   import gnu.mapping.*;
 4   import gnu.lists.*;
 5   import gnu.math.*;
 6   import gnu.expr.*;
 7
 8
 14
 15  public class LispReader extends Lexer
 16  {
 17    public LispReader(LineBufferedReader port)
 18    {
 19      super(port);
 20    }
 21
 22    public LispReader(LineBufferedReader port, SourceMessages messages)
 23    {
 24      super(port, messages);
 25    }
 26
 27
 29    public static Object
  lookupUnit (String  name) 30    {
 31      name = (name + "$unit").intern();
 32      try
 33        {
 34      return Environment.getCurrent().getChecked(name);
 35        }
 36      catch (UnboundLocationException ex)
 37        {
 38      return name;
 39        }
 40    }
 41
 42
 45    final public void readNestedComment (char c1, char c2)
 46         throws java.io.IOException
  , SyntaxException 47    {
 48      int commentNesting = 1;
 49      int startLine = port.getLineNumber();
 50      int startColumn = port.getColumnNumber();
 51      do
 52        {
 53      int c = read ();
 54      if (c == '|')
 55        {
 56          c = read();
 57          if (c == c1)
 58            commentNesting--;
 59        }
 60      else if (c == c1)
 61        {
 62          c = read();
 63          if (c == c2)
 64            commentNesting++;
 65        }
 66      if (c < 0)
 67        {
 68              eofError("unexpected end-of-file in " + c1 + c2
 69                       + " comment starting here",
 70                       startLine + 1, startColumn - 1);
 71          return;
 72        }
 73        } while (commentNesting > 0);
 74    }
 75
 76
 80    static char getReadCase()
 81    {
 82      char read_case;
 83      try
 84        {
 85      String
  read_case_string 86        = Environment.getCurrent().get("symbol-read-case", "P").toString();
 87      read_case = read_case_string.charAt(0);
 88      if (read_case == 'P') ;
 89      else if (read_case == 'u')
 90        read_case = 'U';
 91      else if (read_case == 'd' || read_case == 'l' || read_case == 'L')
 92        read_case = 'D';
 93      else if (read_case == 'i')
 94        read_case = 'I';
 95        }
 96      catch (Exception
  ex) 97        {
 98      read_case = 'P';
 99        }
 100     return read_case;
 101   }
 102
 103   public Object
  readValues (int ch,  ReadTable rtable) 104       throws java.io.IOException
  , SyntaxException 105   {
 106     return readValues(ch, rtable.lookup(ch), rtable);
 107   }
 108
 109
 110   public Object
  readValues (int ch, ReadTableEntry entry, ReadTable rtable) 111       throws java.io.IOException
  , SyntaxException 112   {
 113             int startPos = tokenBufferLength;
 116
 117     if (entry == null)
 118       {
 119         String
  err = ("invalid character #\\"+((char) ch));      if (interactive) fatal(err); 122     else error(err);
 123     return Values.empty;
 124       }
 125     int kind = entry.getKind();
 126     seenEscapes = false;
 127     switch (kind)
 128       {
 129       case ReadTable.WHITESPACE:
 130         return Values.empty;
 132       case ReadTable.TERMINATING_MACRO:
 133       case ReadTable.NON_TERMINATING_MACRO:
 134     Object
  value = entry.read(this, ch, -1); 135     return value;
 136       case ReadTable.CONSTITUENT:
 137         if (ch == rtable.postfixLookupOperator)
 138           {             tokenBufferAppend(ch);
 140             ch = read();
 141           }
 142       case ReadTable.SINGLE_ESCAPE:       case ReadTable.MULTIPLE_ESCAPE:       default:      break;
 146       }
 147
 148     readToken(ch, getReadCase(), rtable);
 149     int endPos = tokenBufferLength;
 150     if (seenEscapes)
 151       return returnSymbol(startPos, endPos, rtable);
 152     else
 153       return handleToken(startPos, endPos, rtable);
 154   }
 155
 156   public static final char TOKEN_ESCAPE_CHAR = '\uffff';
 157
 158
 161   protected boolean seenEscapes;
 162
 163
 164   protected boolean initialColonIsKeyword = true;
 165
 166
 167   protected boolean finalColonIsKeyword = true;
 168
 169   void readToken(int ch, char readCase, ReadTable rtable)
 170       throws java.io.IOException
  , SyntaxException 171   {
 172     boolean inEscapes = false;
 173     for (;; ch = read())
 174       {
 175     if (ch < 0)
 176       {
 177         if (inEscapes)
 178           eofError("unexpected EOF between escapes");
 179         else
 180           break;
 181       }
 182     ReadTableEntry entry = rtable.lookup(ch);
 183     if (entry == null)
 184       {
 185         if (inEscapes)
 186           {
 187         tokenBufferAppend(TOKEN_ESCAPE_CHAR);
 188         tokenBufferAppend(ch);
 189         continue;
 190           }
 191         unread(ch);
 192         break;
 193       }
 194     int kind = entry.getKind();
 195         if (ch == rtable.postfixLookupOperator && ! inEscapes
 196             && validPostfixLookupStart(rtable))
 197           kind = ReadTable.TERMINATING_MACRO;
 198
 199     if (kind == ReadTable.SINGLE_ESCAPE)
 200       {
 201         ch = read();
 202         if (ch < 0)
 203           eofError("unexpected EOF after single escape");
 204         tokenBufferAppend(TOKEN_ESCAPE_CHAR);
 205         tokenBufferAppend(ch);
 206         seenEscapes = true;
 207         continue;
 208       }
 209     if (kind == ReadTable.MULTIPLE_ESCAPE)
 210       {
 211         inEscapes = ! inEscapes;
 212         continue;
 213       }
 214     if (inEscapes)
 215       {
 216                 tokenBufferAppend(TOKEN_ESCAPE_CHAR);
 218         tokenBufferAppend(ch);
 219       }
 220     else
 221       {
 222                 switch (kind)
 224           {
 225           case ReadTable.CONSTITUENT:
 226                   case ReadTable.NON_TERMINATING_MACRO:
 228         if (readCase == 'U'
 229             || (readCase == 'I' && Character.isLowerCase((char) ch)))
 230           ch = Character.toUpperCase((char) ch);
 231         else if (readCase == 'D'
 232              || (readCase == 'I'
 233                  && Character.isUpperCase((char) ch)))
 234           ch = Character.toLowerCase ((char) ch);
 235         tokenBufferAppend(ch);
 236         continue;
 237           case ReadTable.MULTIPLE_ESCAPE:
 238         inEscapes = true;
 239         seenEscapes = true;
 240         continue;
 241           case ReadTable.TERMINATING_MACRO:
 242         unread(ch);
 243         return;
 244           case ReadTable.WHITESPACE:
 245                 unread(ch);
 247         return;
 248           }
 249       }
 250       }
 251   }
 252
 253   public Object
  readObject () 254       throws java.io.IOException
  , SyntaxException 255   {
 256     char saveReadState = ((InPort) port).readState;
 257     int startPos = tokenBufferLength;
 258     ((InPort) port).readState = ' ';
 259     try
 260       {
 261         ReadTable rtable = ReadTable.getCurrent();
 262     for (;;)
 263       {
 264         int line = port.getLineNumber();
 265         int column = port.getColumnNumber();
 266         int ch = port.read();
 267         if (ch < 0)
 268           return Sequence.eofValue;             Object
  value = readValues(ch, rtable); 270         if (value == Values.empty)
 271           continue;
 272         return handlePostfix(value, rtable, line, column);
 273       }
 274       }
 275     finally
 276       {
 277     tokenBufferLength = startPos;
 278     ((InPort) port).readState = saveReadState;
 279       }
 280   }
 281
 282   protected boolean validPostfixLookupStart (ReadTable rtable)
 283       throws java.io.IOException
  284   {
 285     int ch = port.peek();
 286     ReadTableEntry entry;
 287     if (ch < 0 || ch == ':' || (entry = rtable.lookup(ch)) == null
 288         || ch == rtable.postfixLookupOperator)
 289       return false;
 290     int kind = entry.getKind();
 291     return kind == ReadTable.CONSTITUENT
 292       || kind == ReadTable.NON_TERMINATING_MACRO
 293       || kind == ReadTable.MULTIPLE_ESCAPE
 294       || kind == ReadTable.SINGLE_ESCAPE;
 295   }
 296
 297   Object
  handlePostfix (Object  value, ReadTable rtable, int line, int column) 298       throws java.io.IOException
  , SyntaxException 299   {
 300     if (value == QuoteExp.voidExp)
 301       value = Values.empty;
 302     for (;;)
 303       {
 304         int ch = port.peek();
 305         if (ch < 0 || ch != rtable.postfixLookupOperator)
 306           break;
 307                 port.read();
 309         if (! validPostfixLookupStart(rtable))
 310           {
 311             unread();
 312             break;
 313           }
 314         ch = port.read();
 315         Object
  rightOperand = readValues(ch, rtable.lookup(ch), rtable); 316         value = LList.list2(value,
 317                             LList.list2(LispLanguage.quote_sym, rightOperand));
 318         value = PairWithPosition.make(LispLanguage.lookup_sym, value,
 319                                       port.getName(), line+1, column+1);
 320       }
 321     return value;
 322   }
 323
 324   private boolean isPotentialNumber (char[] buffer, int start, int end)
 325   {
 326     int sawDigits = 0;
 327     for (int i = start;  i < end;  i++)
 328       {
 329     char ch = buffer[i];
 330     if (Character.isDigit(ch))
 331       sawDigits++;
 332     else if (ch == '-' || ch == '+')
 333       {
 334         if (i + 1 == end)
 335           return false;
 336       }
 337     else if (ch == '#')
 338       return true;
 339     else if (Character.isLetter(ch) || ch == '/'
 340          || ch == '_' || ch == '^')
 341       {
 342                                 if (i == start)
 346           return false;
 347       }
 348     else if (ch != '.')
 349       return false;
 350       }
 351     return sawDigits > 0;
 352   }
 353
 354   static final int SCM_COMPLEX = 1;
 355   public static final int SCM_NUMBERS = SCM_COMPLEX;
 356
 357
 369   public static Object
  parseNumber(char[] buffer, int start, int count, 370                    char exactness, int radix, int flags)
 371   {
 372     int end = start + count;
 373     int pos = start;
 374     if (pos >= end)
 375       return "no digits";
 376     char ch = buffer[pos++];
 377     while (ch == '#')
 378       {
 379     if (pos >= end)
 380       return "no digits";
 381     ch = buffer[pos++];
 382     switch (ch)
 383       {
 384       case 'b':  case 'B':
 385         if (radix != 0)
 386           return "duplicate radix specifier";
 387         radix = 2;
 388         break;
 389       case 'o':  case 'O':
 390         if (radix != 0)
 391           return "duplicate radix specifier";
 392         radix = 8;
 393         break;
 394       case 'd':  case 'D':
 395         if (radix != 0)
 396           return "duplicate radix specifier";
 397         radix = 10;
 398         break;
 399       case 'x':  case 'X':
 400         if (radix != 0)
 401           return "duplicate radix specifier";
 402         radix = 16;
 403         break;
 404       case 'e':  case 'E':
 405       case 'i':  case 'I':
 406         if (exactness != '\0')
 407           {
 408         if (exactness == ' ')
 409           return "non-prefix exactness specifier";
 410         else
 411           return "duplicate exactness specifier";
 412           }
 413         exactness = ch;
 414         break;
 415       default:
 416         int value = 0;
 417         for (;;)
 418           {
 419         int dig = Character.digit(ch, 10);
 420         if (dig < 0)
 421           break;
 422         value = 10 * value + dig;
 423         if (pos >= end)
 424           return "missing letter after '#'";
 425         ch = buffer[pos++];
 426           }
 427         if (ch == 'R' || ch == 'r')
 428           {
 429         if (radix != 0)
 430           return "duplicate radix specifier";
 431         if (value < 2 || value > 35)
 432           return "invalid radix specifier";
 433         radix = value;
 434         break;
 435           }
 436         return "unknown modifier '#" + ch + '\'';
 437       }
 438     if (pos >= end)
 439       return "no digits";
 440     ch = buffer[pos++];
 441       }
 442     if (exactness == '\0')
 443       exactness = ' ';
 444     if (radix == 0)
 445       {
 446     for (int i = count;  ; )
 447       {
 448         if (--i < 0)
 449           {
 450                         radix = 10;
 453         break;
 454           }
 455         if (buffer[start+i] == '.')
 456           {
 457         radix = 10;
 458         break;
 459           }
 460       }
 461       }
 462
 463     boolean negative = ch == '-';
 464     boolean numeratorNegative = negative;
 465     if (ch == '-' || ch == '+')
 466       {
 467     if (pos >= end)
 468       return "no digits following sign";
 469     ch = buffer[pos++];
 470       }
 471
 472         if ((ch == 'i' || ch == 'I') && pos == end && start == pos - 2
 474     && (flags & SCM_COMPLEX) != 0)
 475       {
 476     char sign = buffer[start];
 477     if (sign != '+' && sign != '-')
 478       return "no digits";
 479     if (exactness == 'i' || exactness == 'I')
 480       return new DComplex(0, negative ? -1 : 1);
 481     return negative ? Complex.imMinusOne() : Complex.imOne();
 482       }
 483
 484     int realStart = pos - 1;
 485     boolean hash_seen = false;
 486     char exp_seen = '\000';
 487     int digits_start = -1;
 488     int decimal_point = -1;
 489     boolean copy_needed = false;
 490     boolean underscore_seen = false;
 491     IntNum numerator = null;
 492     long lvalue = 0;
 493   loop:
 494     for (;;)
 495       {
 496     int digit = Character.digit(ch, radix);
 497     if (digit >= 0)
 498       {
 499         if (hash_seen && decimal_point < 0)
 500           return "digit after '#' in number";
 501         if (digits_start < 0)
 502           digits_start = pos - 1;
 503         lvalue = radix * lvalue + digit;
 504       }
 505     else
 506       {
 507         switch (ch)
 508           {
 509
 514
 523           case '.':
 524         if (decimal_point >= 0)
 525           return "duplicate '.' in number";
 526         if (radix != 10)
 527           return "'.' in non-decimal number";
 528         decimal_point = pos - 1;
 529         break;
 530           case 'e': case 's': case 'f': case 'd': case 'l':
 531           case 'E': case 'S': case 'F': case 'D': case 'L':
 532         if (pos == end || radix != 10)
 533           {
 534             pos--;
 535             break loop;
 536           }
 537         char next = buffer[pos];
 538         if (next == '+' || next == '-')
 539           {
 540             if (++ pos >= end
 541             || Character.digit(buffer[pos], 10) < 0)
 542               return "missing exponent digits";
 543           }
 544         else if (Character.digit(next, 10) < 0)
 545           {
 546             pos--;
 547             break loop;
 548           }
 549         if (exp_seen != '\000')
 550           return "duplicate exponent";
 551         if (radix != 10)
 552           return "exponent in non-decimal number";
 553         if (digits_start < 0)
 554           return "mantissa with no digits";
 555         exp_seen = ch;
 556         for (;;)
 557           {
 558             pos++;
 559             if (pos >= end || Character.digit(buffer[pos], 10) < 0)
 560               break loop;
 561           }
 562           case '/':
 563         if (numerator != null)
 564           return "multiple fraction symbol '/'";
 565         if (digits_start < 0)
 566           return "no digits before fraction symbol '/'";
 567         if (exp_seen != '\000' || decimal_point >= 0)
 568           return "fraction symbol '/' following exponent or '.'";
 569         numerator = valueOf(buffer, digits_start, pos - digits_start,
 570                     radix, negative, lvalue);
 571         digits_start = -1;
 572         lvalue = 0;
 573         negative = false;
 574         hash_seen = false;
 575         underscore_seen = false;
 576         break;
 577           default:
 578         pos--;
 579         break loop;
 580           }
 581       }
 582     if (pos == end)
 583       break;
 584     ch = buffer[pos++];
 585       }
 586
 587     if (digits_start < 0)
 588       return "no digits";
 589
 590     if (hash_seen || underscore_seen)
 591       {
 592           }
 594
 595     boolean inexact = (exactness == 'i' || exactness == 'I'
 596                || (exactness == ' ' && hash_seen));
 597     RealNum number = null;
 598     if (exp_seen != '\000' || decimal_point >= 0)
 599       {
 600     if (digits_start > decimal_point && decimal_point >= 0)
 601       digits_start = decimal_point;
 602     if (numerator != null)
 603       return "floating-point number after fraction symbol '/'";
 604     String
  str = new String  (buffer, digits_start, pos - digits_start); 605     double d = Convert.parseDouble(str);
 606     number = new DFloNum(negative ? - d : d);
 607       }
 608     else
 609       {
 610     IntNum iresult = valueOf(buffer, digits_start, pos - digits_start,
 611                  radix, negative, lvalue);
 612     if (numerator == null)
 613       number = iresult;
 614     else
 615       {
 616                         if (iresult.isZero ())
 619           {
 620         boolean numeratorZero = numerator.isZero();
 621         if (inexact)
 622           number =  new DFloNum ((numeratorZero ? Double.NaN
 623                       : numeratorNegative ? Double.NEGATIVE_INFINITY
 624                       : Double.POSITIVE_INFINITY));
 625         else if (numeratorZero)
 626           return "0/0 is undefined";
 627         else
 628           number = RatNum.make(numerator, iresult);
 629           }
 630         else
 631           {
 632         number = RatNum.make(numerator, iresult);
 633           }
 634       }
 635     if (inexact && number.isExact())
 636             number = new DFloNum(numeratorNegative && number.isZero() ? -0.0
 638                    : number.doubleValue());
 639       }
 640
 641     if (exactness == 'e' || exactness == 'E')
 642       number = number.toExact();
 643
 644     if (pos < end)
 645       {
 646     ch = buffer[pos++];
 647
 648     if (ch == '@')
 649       {
 650         Object
  angle = parseNumber(buffer, pos, end - pos, 651                        exactness, 10, flags);
 652         if (angle instanceof String
  ) 653           return angle;
 654         if (! (angle instanceof RealNum))
 655           return "invalid complex polar constant";
 656         RealNum rangle = (RealNum) angle;
 657
 659         if (number.isZero () && !rangle.isExact ())
 660           return new DFloNum (0.0);
 661
 662         return Complex.polar (number, rangle);
 663       }
 664
 665     if (ch == '-' || ch == '+')
 666       {
 667         pos--;
 668         Object
  imag = parseNumber(buffer, pos, end - pos, 669                       exactness, 10, flags);
 670         if (imag instanceof String
  ) 671           return imag;
 672         if (! (imag instanceof Complex))
 673           return "invalid numeric constant ("+imag+")";
 674         Complex cimag = (Complex) imag;
 675         RealNum re = cimag.re();
 676         if (! re.isZero())
 677           return "invalid numeric constant";
 678         return Complex.make(number, cimag.im());
 679       }
 680
 681     int lcount = 0;
 682     for (;;)
 683       {
 684         if (! Character.isLetter(ch))
 685           {
 686         pos--;
 687         break;
 688           }
 689         lcount++;
 690         if (pos == end)
 691           break;
 692         ch = buffer[pos++];
 693       }
 694
 695     if (lcount == 1)
 696       {
 697         char prev = buffer[pos-1];
 698         if (prev == 'i' || prev == 'I')
 699           {
 700         if (pos < end)
 701           return "junk after imaginary suffix 'i'";
 702         return Complex.make(IntNum.zero (), number);
 703           }
 704       }
 705     if (lcount > 0)
 706       {
 707         Object
  unit = null; 708         for (;;)
 709           {
 710         String
  word = new String  (buffer, pos - lcount, lcount); 711         Object
  u = lookupUnit(word); 712
 713         int power = 1;
 714         if (pos < end)
 715           {
 716             ch = buffer[pos];
 717             if (ch == '^' && ++pos < end)
 718               ch = buffer[pos];
 719             boolean neg = ch == '-';
 720             if ((ch == '-' || ch == '+') && ++pos < end)
 721               ch = buffer[pos];
 722             power = -1;
 723             for (;;)
 724               {
 725             int d = Character.digit(ch, 10);
 726             if (d < 0)
 727               {
 728                 if (power < 0)
 729                   return "junk after unit name";
 730                 break;
 731               }
 732             power = power < 0 ? d  : 10 * power + d;
 733             if (++pos == end)
 734               break;
 735             if (power > 1000000)
 736               return "unit power too large";
 737             ch = buffer[pos];
 738               }
 739             if (neg) power = -power;
 740           }
 741
 742                 if (power != 1)
 744           {
 745             if (u instanceof Unit)
 746               u = Unit.pow((Unit) u, power);
 747             else
 748               u = LList.list3("expt", u, IntNum.make(power));
 749           }
 750         if (unit == null)
 751           unit = u;
 752         else if (u instanceof Unit && unit instanceof Unit)
 753           unit = Unit.times((Unit) unit, (Unit) u);
 754         else
 755           unit = LList.list3("*", unit, u);
 756         if (pos >= end)
 757           break;
 758         ch = buffer[pos++];
 759         if (ch == '*')
 760           {
 761             if (pos == end)
 762               return "end of token after '*'";
 763             ch = buffer[pos++];
 764           }
 765         lcount = 0;
 766         for (;;)
 767           {
 768             if (! Character.isLetter(ch))
 769               {
 770             pos--;
 771             break;
 772               }
 773             lcount++;
 774             if (pos == end)
 775               break;
 776             ch = buffer[pos++];
 777           }
 778         if (lcount == 0)
 779           return "excess junk after unit";
 780           }
 781
 782         if (unit == null)
 783           return "expected unit";
 784         else if (unit instanceof Unit)
 785           return Quantity.make(number, (Unit) unit);
 786         else
 787           return LList.list3("*", number, unit);
 788       }
 789     else
 790       return "excess junk after number";
 791
 792       }
 793     return number;
 794   }
 795
 796   private static IntNum valueOf (char[] buffer, int digits_start,
 797                  int number_of_digits,
 798                  int radix, boolean negative,
 799                  long lvalue)
 800   {
 801                 if (number_of_digits + radix <= 28)
 805       return IntNum.make(negative ? - lvalue : lvalue);
 806     else
 807       return IntNum.valueOf(buffer, digits_start, number_of_digits,
 808                 radix, negative);
 809   }
 810
 811   protected Object
  returnSymbol(int startPos, int endPos, ReadTable rtable) 812   {
 813     char readCase = getReadCase();
 814     if (readCase == 'I')
 815       {
 816     int upperCount = 0;
 817     int lowerCount = 0;
 818     for (int i = startPos;  i < endPos;  i++)
 819       {
 820         char ch = tokenBuffer[i];
 821         if (ch == TOKEN_ESCAPE_CHAR)
 822           i++;
 823         else if (Character.isLowerCase(ch))
 824           lowerCount++;
 825         else if (Character.isUpperCase(ch))
 826           upperCount++;
 827       }
 828     if (lowerCount == 0)
 829       readCase = 'D';
 830     else if (upperCount == 0)
 831       readCase = 'U';
 832     else
 833       readCase = 'P';
 834       }
 835
 836     int packageMarker = -1;
 837     int j = startPos;
 838     for (int i = startPos;  i < endPos;  i++)
 839       {
 840     char ch = tokenBuffer[i];
 841     if (ch == TOKEN_ESCAPE_CHAR)
 842       {
 843         if (++ i < endPos)
 844           tokenBuffer[j++] = tokenBuffer[i];
 845         continue;
 846       }
 847     if (ch == ':')
 848       packageMarker = packageMarker >= 0 ? -1 : j;
 849     else if (readCase == 'U')
 850       ch = Character.toUpperCase(ch);
 851     else if (readCase == 'D')
 852       ch = Character.toLowerCase(ch);
 853     tokenBuffer[j++] = ch;
 854       }
 855     endPos = j;
 856
 857     int len = endPos - startPos;
 858
 859     if (initialColonIsKeyword && packageMarker == startPos && len > 1)
 860       {
 861     startPos++;
 862     String
  str = new String  (tokenBuffer, startPos, endPos-startPos); 863     return Keyword.make(str.intern());
 864     }
 865     if (finalColonIsKeyword && packageMarker == endPos - 1 && len > 1)
 866       {
 867     String
  str = new String  (tokenBuffer, startPos, len - 1); 868     return Keyword.make(str.intern());
 869       }
 870     return rtable.makeSymbol(new String
  (tokenBuffer, startPos, len)); 871   }
 872
 873
 874   public Object
  handleToken(int startPos, int endPos,  ReadTable rtable) 875   {
 876     Object
  value = parseNumber(tokenBuffer, startPos, endPos - startPos, 877                    '\0', 0, SCM_NUMBERS);
 878     if (value != null && ! (value instanceof String
  )) 879       return value;
 880     if (isPotentialNumber(tokenBuffer, startPos, endPos))
 881       {
 882     error(value == null ? "not a valid number"
 883           : "not a valid number: " + value);
 884     return IntNum.zero();
 885       }
 886     return returnSymbol(startPos, endPos, rtable);
 887   }
 888
 889
 892   public int readEscape()
 893     throws java.io.IOException
  , SyntaxException 894   {
 895     int c = read();
 896     if (c < 0)
 897       {
 898     eofError("unexpected EOF in character literal");
 899     return -1;
 900       }
 901     return readEscape(c);
 902   }
 903
 904   public final int readEscape(int c)
 905     throws java.io.IOException
  , SyntaxException 906   {
 907     switch ((char) c)
 908       {
 909       case 'a':  c =  7;  break;        case 'b':  c =  8;  break;        case 't':  c =  9;  break;        case 'n':  c = 10;  break;        case 'v':  c = 11;  break;        case 'f':  c = 12;  break;        case 'r':  c = 13;  break;        case 'e':  c = 27;  break;        case '\"': c = 34;  break;        case '\\': c = 92;  break;        case ' ':     for (;;)
 921       {
 922         c = read();
 923         if (c < 0)
 924           {
 925         eofError("unexpected EOF in character literal");
 926         return -1;
 927           }
 928         if (c == '\n')
 929           return -2;
 930         if (c == '\r')
 931           {
 932         if (peek() == '\n')
 933           skip();
 934         return -2;
 935           }
 936         if (c != ' ' && c != '\t')
 937           {
 938         unread(c);
 939         break;
 940           }
 941       }
 942       case '\r':
 943     if (peek() == '\n')
 944       skip();
 945     return -2;
 946       case '\n':
 947     return -2;
 948       case 'M':
 949     c = read();
 950     if (c != '-')
 951       {
 952         error("Invalid escape character syntax");
 953         return '?';
 954       }
 955     c = read();
 956     if (c == '\\')
 957       c = readEscape();
 958     return c | 0200;
 959       case 'C':
 960     c = read();
 961     if (c != '-')
 962       {
 963         error("Invalid escape character syntax");
 964         return '?';
 965       }
 966
 967       case '^':
 968     c = read();
 969     if (c == '\\')
 970       c = readEscape();
 971     if (c == '?')
 972       return 0177;
 973     return c & (0200 | 037);
 974       case '0':
 975       case '1':
 976       case '2':
 977       case '3':
 978       case '4':
 979       case '5':
 980       case '6':
 981       case '7':
 982
 983     c = c - '0';
 984     for (int count = 0;  ++count < 3; )
 985       {
 986         int d = read();
 987         int v = Character.digit((char) d, 8);
 988         if (v >= 0)
 989           c = (c << 3) + v;
 990         else
 991           {
 992         if (d >= 0)
 993           unread(d);
 994         break;
 995           }
 996       }
 997     break;
 998       case 'u':
 999     c = 0;
 1000    for (int i = 4;  --i >= 0; )
 1001      {
 1002        int d = read ();
 1003        if (d < 0)
 1004          eofError("premature EOF in \\u escape");
 1005        int v = Character.digit ((char) d, 16);
 1006        if (v < 0)
 1007          error("non-hex character following \\u");
 1008        c = 16 * c + v;
 1009      }
 1010    break;
 1011      case 'x':
 1012    c = 0;
 1013
 1014    for (;;)
 1015      {
 1016        int d = read();
 1017        int v = Character.digit((char) d, 16);
 1018        if (v >= 0)
 1019          c = (c << 4) + v;
 1020        else
 1021          {
 1022        if (d >= 0)
 1023          unread(d);
 1024        break;
 1025          }
 1026      }
 1027    break;
 1028      default:  break;
 1029      }
 1030    return c;
 1031  }
 1032
 1033  public final Object
  readObject (int c) 1034      throws java.io.IOException
  , SyntaxException 1035  {
 1036    unread(c);
 1037    return readObject();
 1038  }
 1039
 1040
 1042  public Object
  readCommand () 1043      throws java.io.IOException
  , SyntaxException 1044  {
 1045    return readObject();
 1046  }
 1047
 1048  protected Object
  makeNil () 1049  {
 1050    return LList.Empty;
 1051  }
 1052
 1053  protected Object
  makePair (Object  car, int line, int column) 1054  {
 1055    return PairWithPosition.make(car, LList.Empty,
 1056                                 port.getName(), line + 1, column + 1);
 1057  }
 1058
 1059  public Object
  makePair (Object  car, Object  cdr) 1060  {
 1061    Object
  pair = makePair(car, -1, -1); 1062    setCdr(pair, cdr);
 1063    return pair;
 1064  }
 1065
 1066  protected void setCdr (Object
  pair, Object  cdr) 1067  {
 1068    ((Pair) pair).cdr = cdr;
 1069  }
 1070
 1071
 1076  public static Object
  readNumberWithRadix(int previous, LispReader reader, int radix) 1077    throws java.io.IOException
  , SyntaxException 1078  {
 1079    int startPos = reader.tokenBufferLength - previous;
 1080    reader.readToken(reader.read(), 'P', ReadTable.getCurrent());
 1081    int endPos = reader.tokenBufferLength;
 1082    if (startPos == endPos)
 1083      {
 1084    reader.error("missing numeric token");
 1085    return IntNum.zero();
 1086      }
 1087    Object
  result = LispReader.parseNumber(reader.tokenBuffer, startPos, 1088                       endPos - startPos, '\0', radix, 0);
 1089    if (result instanceof String
  ) 1090      {
 1091    reader.error((String
  ) result); 1092    return IntNum.zero();
 1093      }
 1094    else if (result == null)
 1095      {
 1096    reader.error("invalid numeric constant");
 1097    return IntNum.zero();
 1098      }
 1099    else
 1100      return result;
 1101  }
 1102
 1103  public static Object
  readCharacter (LispReader reader) 1104    throws java.io.IOException
  , SyntaxException 1105  {
 1106    int ch = reader.read();
 1107    if (ch < 0)
 1108      reader.eofError("unexpected EOF in character literal");
 1109    int startPos = reader.tokenBufferLength;
 1110    reader.tokenBufferAppend(ch);
 1111    reader.readToken(reader.read(), 'D', ReadTable.getCurrent());
 1112    int length = reader.tokenBufferLength - startPos;
 1113    if (length == 1)
 1114      return Char.make(reader.tokenBuffer[startPos]);
 1115    String
  name = new String  (reader.tokenBuffer, startPos, length); 1116    ch = Char.nameToChar(name);
 1117    if (ch >= 0)
 1118      return Char.make(ch);
 1119    ch = Character.digit(reader.tokenBuffer[startPos], 8);
 1120    if (ch >= 0)
 1121      {
 1122    int value = ch;
 1123    for (int i = 1;  ;  i++)
 1124      {
 1125        if (i == length)
 1126          return Char.make(value);
 1127        ch = Character.digit(reader.tokenBuffer[startPos + i], 8);
 1128        if (ch < 0)
 1129          break;
 1130        value = 8 * value + ch;
 1131      }
 1132      }
 1133    reader.error("unknown character name: " + name);
 1134    return Char.make('?');
 1135  }
 1136
 1137  public static Object
  readSpecial (LispReader reader) 1138    throws java.io.IOException
  , SyntaxException 1139  {
 1140    int ch = reader.read();
 1141    if (ch < 0)
 1142      reader.eofError("unexpected EOF in #! special form");
 1143
 1144
 1145    if (ch == '/'
 1146    && reader.getLineNumber() == 0
 1147    && reader.getColumnNumber() == 3)
 1148      {
 1149    ReaderIgnoreRestOfLine.getInstance().read(reader, '#', 1);
 1150    return Values.empty;
 1151      }
 1152
 1153    int startPos = reader.tokenBufferLength;
 1154    reader.tokenBufferAppend(ch);
 1155    reader.readToken(reader.read(), 'D', ReadTable.getCurrent());
 1156    int length = reader.tokenBufferLength - startPos;
 1157    String
  name = new String  (reader.tokenBuffer, startPos, length); 1158    if (name.equals("optional"))
 1159      return Special.optional;
 1160    if (name.equals("rest"))
 1161      return Special.rest;
 1162    if (name.equals("key"))
 1163      return Special.key;
 1164    if (name.equals("eof"))
 1165      return Special.eof;
 1166    if (name.equals("void"))
 1167            return QuoteExp.voidExp;
 1169    if (name.equals("default"))
 1170      return Special.dfault;
 1171    if (name.equals("undefined"))
 1172      return Special.undefined;
 1173    if (name.equals("null"))
 1174      return null;
 1175    reader.error("unknown named constant #!"+name);
 1176    return null;
 1177  }
 1178
 1179  public static SimpleVector
 1180  readSimpleVector(LispReader reader, char kind)
 1181    throws java.io.IOException
  , SyntaxException 1182  {
 1183    int size = 0;
 1184    int ch;
 1185    for (;;)
 1186      {
 1187    ch = reader.read();
 1188    if (ch < 0)
 1189      reader.eofError("unexpected EOF reading uniform vector");
 1190    int digit = Character.digit((char) ch, 10);
 1191    if (digit < 0)
 1192      break;
 1193    size = size * 10 + digit;
 1194      }
 1195    if (! (size == 8 || size == 16 || size == 32 || size == 64)
 1196        || (kind == 'F' && size < 32)
 1197        || ch != '(')
 1198      {
 1199        reader.error("invalid uniform vector syntax");
 1200        return null;
 1201      }
 1202    Object
  list = ReaderParens.readList(reader, '(', -1, ')'); 1203    int len = LList.listLength(list, false);
 1204    if (len < 0)
 1205      {
 1206        reader.error("invalid elements in uniform vector syntax");
 1207        return null;
 1208      }
 1209    Sequence q = (Sequence) list;
 1210    switch (kind)
 1211      {
 1212      case 'F':
 1213        switch (size)
 1214          {
 1215          case 32:  return new F32Vector(q);
 1216          case 64:  return new F64Vector(q);
 1217          }
 1218      case 'S':
 1219        switch (size)
 1220          {
 1221          case  8:  return new S8Vector(q);
 1222          case 16:  return new S16Vector(q);
 1223          case 32:  return new S32Vector(q);
 1224          case 64:  return new S64Vector(q);
 1225          }
 1226      case 'U':
 1227        switch (size)
 1228          {
 1229          case  8:  return new U8Vector(q);
 1230          case 16:  return new U16Vector(q);
 1231          case 32:  return new U32Vector(q);
 1232          case 64:  return new U64Vector(q);
 1233          }
 1234      }
 1235    return null;
 1236  }
 1237}
 1238
                                                                                                                                                                                                             |                                                                       
 
 
 
 
 
                                                                                   Popular Tags                                                                                                                                                                                              |