home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 110 / EnigmaAmiga110CD.iso / indispensabili / utility / apdf / xpdf-0.80 / xpdf / lexer.cc < prev    next >
C/C++ Source or Header  |  1998-11-27  |  9KB  |  454 lines

  1. //========================================================================
  2. //
  3. // Lexer.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8.  
  9. #ifdef __GNUC__
  10. #pragma implementation
  11. #endif
  12.  
  13. #include <stdlib.h>
  14. #include <stddef.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include "Lexer.h"
  18. #include "Error.h"
  19.  
  20. //------------------------------------------------------------------------
  21.  
  22. // A '1' in this array means the corresponding character ends a name
  23. // or command.
  24. static char endOfNameChars[128] = {
  25.   0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,   // 0x
  26.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 1x
  27.   1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1,   // 2x
  28.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,   // 3x
  29.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 4x
  30.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,   // 5x
  31.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 6x
  32.   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0    // 7x
  33. };
  34.  
  35. //------------------------------------------------------------------------
  36. // Lexer
  37. //------------------------------------------------------------------------
  38.  
  39. Lexer::Lexer(Stream *str) {
  40.   Object obj;
  41.  
  42.   curStr.initStream(str);
  43.   streams = new Array();
  44.   streams->add(curStr.copy(&obj));
  45.   strPtr = 0;
  46.   freeArray = gTrue;
  47.   curStr.streamReset();
  48. }
  49.  
  50. Lexer::Lexer(Object *obj) {
  51.   Object obj2;
  52.  
  53.   if (obj->isStream()) {
  54.     streams = new Array();
  55.     freeArray = gTrue;
  56.     streams->add(obj->copy(&obj2));
  57.   } else {
  58.     streams = obj->getArray();
  59.     freeArray = gFalse;
  60.   }
  61.   strPtr = 0;
  62.   if (streams->getLength() > 0) {
  63.     streams->get(strPtr, &curStr);
  64.     curStr.streamReset();
  65.   }
  66. }
  67.  
  68. Lexer::~Lexer() {
  69.   if (!curStr.isNone())
  70.     curStr.free();
  71.   if (freeArray)
  72.     delete streams;
  73. }
  74.  
  75. int Lexer::getChar() {
  76.   int c;
  77.  
  78.   c = EOF;
  79.   while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) {
  80.     curStr.free();
  81.     ++strPtr;
  82.     if (strPtr < streams->getLength()) {
  83.       streams->get(strPtr, &curStr);
  84.       curStr.streamReset();
  85.     }
  86.   }
  87.   return c;
  88. }
  89.  
  90. int Lexer::lookChar() {
  91.   int c;
  92.  
  93.   c = EOF;
  94.   while (!curStr.isNone() && (c = curStr.streamLookChar()) == EOF) {
  95.     curStr.free();
  96.     ++strPtr;
  97.     if (strPtr < streams->getLength()) {
  98.       streams->get(strPtr, &curStr);
  99.       curStr.streamReset();
  100.     }
  101.   }
  102.   return c;
  103. }
  104.  
  105. Object *Lexer::getObj(Object *obj) {
  106.   char *p;
  107.   int c, c2;
  108.   GBool comment, neg, done;
  109.   int numParen;
  110.   int xi;
  111.   double xf, scale;
  112.   GString *s;
  113.   int n, m;
  114.  
  115.   // skip whitespace and comments
  116.   comment = gFalse;
  117.   while (1) {
  118.     if ((c = getChar()) == EOF)
  119.       return obj->initEOF();
  120.     if (comment) {
  121.       if (c == '\r' || c == '\n')
  122.     comment = gFalse;
  123.     } else if (c == '%') {
  124.       comment = gTrue;
  125.     } else if (!isspace(c)) {
  126.       break;
  127.     }
  128.   }
  129.  
  130.   // start reading token
  131.   switch (c) {
  132.  
  133.   // number
  134.   case '0': case '1': case '2': case '3': case '4':
  135.   case '5': case '6': case '7': case '8': case '9':
  136.   case '-': case '.':
  137.     neg = gFalse;
  138.     xi = 0;
  139.     if (c == '-') {
  140.       neg = gTrue;
  141.     } else if (c == '.') {
  142.       goto doReal;
  143.     } else {
  144.       xi = c - '0';
  145.     }
  146.     while (1) {
  147.       c = lookChar();
  148.       if (isdigit(c)) {
  149.     getChar();
  150.     xi = xi * 10 + (c - '0');
  151.       } else if (c == '.') {
  152.     getChar();
  153.     goto doReal;
  154.       } else {
  155.     break;
  156.       }
  157.     }
  158.     if (neg)
  159.       xi = -xi;
  160.     obj->initInt(xi);
  161.     break;
  162.   doReal:
  163.     xf = xi;
  164.     scale = 0.1;
  165.     while (1) {
  166.       c = lookChar();
  167.       if (!isdigit(c))
  168.     break;
  169.       getChar();
  170.       xf = xf + scale * (c - '0');
  171.       scale *= 0.1;
  172.     }
  173.     if (neg)
  174.       xf = -xf;
  175.     obj->initReal(xf);
  176.     break;
  177.  
  178.   // string
  179.   case '(':
  180.     p = tokBuf;
  181.     n = 0;
  182.     numParen = 1;
  183.     done = gFalse;
  184.     s = NULL;
  185.     do {
  186.       c2 = EOF;
  187.       switch (c = getChar()) {
  188.  
  189.       case EOF:
  190.       case '\r':
  191.       case '\n':
  192.     error(getPos(), "Unterminated string");
  193.     done = gTrue;
  194.     break;
  195.  
  196.       case '(':
  197.     ++numParen;
  198.     break;
  199.  
  200.       case ')':
  201.     if (--numParen == 0)
  202.       done = gTrue;
  203.     break;
  204.  
  205.       case '\\':
  206.     switch (c = getChar()) {
  207.     case 'n':
  208.       c2 = '\n';
  209.       break;
  210.     case 'r':
  211.       c2 = '\r';
  212.       break;
  213.     case 't':
  214.       c2 = '\t';
  215.       break;
  216.     case 'b':
  217.       c2 = '\b';
  218.       break;
  219.     case 'f':
  220.       c2 = '\f';
  221.       break;
  222.     case '\\':
  223.     case '(':
  224.     case ')':
  225.       c2 = c;
  226.       break;
  227.     case '0': case '1': case '2': case '3':
  228.     case '4': case '5': case '6': case '7':
  229.       c2 = c - '0';
  230.       c = lookChar();
  231.       if (c >= '0' && c <= '7') {
  232.         getChar();
  233.         c2 = (c2 << 3) + (c - '0');
  234.         c = lookChar();
  235.         if (c >= '0' && c <= '7') {
  236.           getChar();
  237.           c2 = (c2 << 3) + (c - '0');
  238.         }
  239.       }
  240.       break;
  241.     case '\r':
  242.       c = lookChar();
  243.       if (c == '\n')
  244.         getChar();
  245.       break;
  246.     case '\n':
  247.       break;
  248.     case EOF:
  249.       error(getPos(), "Unterminated string");
  250.       done = gTrue;
  251.       break;
  252.     default:
  253.       c2 = c;
  254.       break;
  255.     }
  256.     break;
  257.  
  258.       default:
  259.     c2 = c;
  260.     break;
  261.       }
  262.  
  263.       if (c2 != EOF) {
  264.     if (n == tokBufSize) {
  265.       if (!s)
  266.         s = new GString(tokBuf, tokBufSize);
  267.       else
  268.         s->append(tokBuf, tokBufSize);
  269.       p = tokBuf;
  270.       n = 0;
  271.     }
  272.     *p++ = (char)c2;
  273.     ++n;
  274.       }
  275.     } while (!done);
  276.     if (!s)
  277.       s = new GString(tokBuf, n);
  278.     else
  279.       s->append(tokBuf, n);
  280.     obj->initString(s);
  281.     break;
  282.  
  283.   // name
  284.   case '/':
  285.     p = tokBuf;
  286.     n = 0;
  287.     while ((c = lookChar()) != EOF && !(c < 128 && endOfNameChars[c])) {
  288.       getChar();
  289.       if (c == '#') {
  290.     c2 = lookChar();
  291.     if (c2 >= '0' && c2 <= '9')
  292.       c = c2 - '0';
  293.     else if (c2 >= 'A' && c2 <= 'F')
  294.       c = c2 - 'A' + 10;
  295.     else if (c2 >= 'a' && c2 <= 'f')
  296.       c = c2 - 'a' + 10;
  297.     else
  298.       goto notEscChar;
  299.     getChar();
  300.     c <<= 4;
  301.     c2 = getChar();
  302.     if (c2 >= '0' && c2 <= '9')
  303.       c += c2 - '0';
  304.     else if (c2 >= 'A' && c2 <= 'F')
  305.       c += c2 - 'A' + 10;
  306.     else if (c2 >= 'a' && c2 <= 'f')
  307.       c += c2 - 'a' + 10;
  308.     else
  309.       error(getPos(), "Illegal digit in hex char in name");
  310.       }
  311.      notEscChar:
  312.       if (++n == tokBufSize) {
  313.     error(getPos(), "Name token too long");
  314.     break;
  315.       }
  316.       *p++ = c;
  317.     }
  318.     *p = '\0';
  319.     obj->initName(tokBuf);
  320.     break;
  321.  
  322.   // array punctuation
  323.   case '[':
  324.   case ']':
  325.     tokBuf[0] = c;
  326.     tokBuf[1] = '\0';
  327.     obj->initCmd(tokBuf);
  328.     break;
  329.  
  330.   // hex string or dict punctuation
  331.   case '<':
  332.     c = lookChar();
  333.  
  334.     // dict punctuation
  335.     if (c == '<') {
  336.       getChar();
  337.       tokBuf[0] = tokBuf[1] = '<';
  338.       tokBuf[2] = '\0';
  339.       obj->initCmd(tokBuf);
  340.  
  341.     // hex string
  342.     } else {
  343.       p = tokBuf;
  344.       m = n = 0;
  345.       c2 = 0;
  346.       s = NULL;
  347.       while (1) {
  348.     c = getChar();
  349.     if (c == '>') {
  350.       break;
  351.     } else if (c == EOF) {
  352.       error(getPos(), "Unterminated hex string");
  353.       break;
  354.     } else if (!isspace(c)) {
  355.       c2 = c2 << 4;
  356.       if (c >= '0' && c <= '9')
  357.         c2 += c - '0';
  358.       else if (c >= 'A' && c <= 'F')
  359.         c2 += c - 'A' + 10;
  360.       else if (c >= 'a' && c <= 'f')
  361.         c2 += c - 'a' + 10;
  362.       else
  363.         error(getPos(), "Illegal character <%02x> in hex string", c);
  364.       if (++m == 2) {
  365.         if (n == tokBufSize) {
  366.           if (!s)
  367.         s = new GString(tokBuf, tokBufSize);
  368.           else
  369.         s->append(tokBuf, tokBufSize);
  370.           p = tokBuf;
  371.           n = 0;
  372.         }
  373.         *p++ = (char)c2;
  374.         ++n;
  375.         c2 = 0;
  376.         m = 0;
  377.       }
  378.     }
  379.       }
  380.       if (!s)
  381.     s = new GString(tokBuf, n);
  382.       else
  383.     s->append(tokBuf, n);
  384.       if (m == 1)
  385.     s->append((char)(c2 << 4));
  386.       obj->initString(s);
  387.     }
  388.     break;
  389.  
  390.   // dict punctuation
  391.   case '>':
  392.     c = lookChar();
  393.     if (c == '>') {
  394.       getChar();
  395.       tokBuf[0] = tokBuf[1] = '>';
  396.       tokBuf[2] = '\0';
  397.       obj->initCmd(tokBuf);
  398.     } else {
  399.       error(getPos(), "Illegal character '>'");
  400.       obj->initError();
  401.     }
  402.     break;
  403.  
  404.   // error
  405.   case ')':
  406.   case '{':
  407.   case '}':
  408.     error(getPos(), "Illegal character '%c'", c);
  409.     obj->initError();
  410.     break;
  411.  
  412.   // command
  413.   default:
  414.     p = tokBuf;
  415.     *p++ = c;
  416.     n = 1;
  417.     while ((c = lookChar()) != EOF && !(c < 128 && endOfNameChars[c])) {
  418.       getChar();
  419.       if (++n == tokBufSize) {
  420.     error(getPos(), "Command token too long");
  421.     break;
  422.       }
  423.       *p++ = c;
  424.     }
  425.     *p = '\0';
  426.     if (tokBuf[0] == 't' && !strcmp(tokBuf, "true"))
  427.       obj->initBool(gTrue);
  428.     else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false"))
  429.       obj->initBool(gFalse);
  430.     else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null"))
  431.       obj->initNull();
  432.     else
  433.       obj->initCmd(tokBuf);
  434.     break;
  435.   }
  436.  
  437.   return obj;
  438. }
  439.  
  440. void Lexer::skipToNextLine() {
  441.   int c;
  442.  
  443.   while (1) {
  444.     c = getChar();
  445.     if (c == EOF || c == '\n')
  446.       return;
  447.     if (c == '\r') {
  448.       if ((c = lookChar()) == '\n')
  449.     getChar();
  450.       return;
  451.     }
  452.   }
  453. }
  454.