home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / lyx-0.13.2.tar.gz / lyx-0.13.2.tar / lyx-0.13.2 / src / lyxlex.C < prev    next >
C/C++ Source or Header  |  1998-04-23  |  10KB  |  519 lines

  1. //  Generalized simple lexical analizer.
  2. //  It can be used for simple syntax parsers, like lyxrc,
  3. //  texclass and others to come.   [asierra30/03/96]
  4. //
  5. //   (C) 1996 Lyx Team.
  6.  
  7. #include <config.h>
  8. //#include "definitions.h"
  9.  
  10. #include <stdlib.h>
  11. #include <string.h>
  12.  
  13. #ifdef __GNUG__
  14. #pragma implementation "lyxlex.h"
  15. #endif
  16.  
  17. #include "lyxlex.h"
  18. #include "error.h"
  19. #include "filetools.h"
  20.  
  21. //     $Id: lyxlex.C,v 1.1.1.1 1998/04/23 16:02:53 larsbj Exp $    
  22.  
  23. #if !defined(lint) && !defined(WITH_WARNINGS)
  24. static char vcid[] = "$Id: lyxlex.C,v 1.1.1.1 1998/04/23 16:02:53 larsbj Exp $";
  25. #endif /* lint */
  26.  
  27.  
  28. LyXLex::LyXLex(keyword_item* tab, int num)
  29.     : table(tab), no_items(num)
  30. {
  31.     file = NULL;
  32.     owns_file = false;
  33.     status = 0;
  34.     pushed = NULL;
  35. }
  36.  
  37.  
  38. void LyXLex::pushTable(keyword_item* tab, int num)
  39. {
  40.     pushed_table *tmppu = new pushed_table;
  41.     tmppu->next = pushed;
  42.     tmppu->table_elem = table;
  43.     tmppu->table_siz = no_items;
  44.     pushed = tmppu;
  45.     table = tab;
  46.     no_items = num;
  47. }
  48.  
  49.  
  50. void LyXLex::popTable()
  51. {
  52.     if (pushed == NULL)
  53.         lyxerr.print("LyXLex error: nothing to pop!");
  54.  
  55.     pushed_table *tmp;
  56.     tmp = pushed;
  57.     table = tmp->table_elem;
  58.     no_items = tmp->table_siz;
  59.     tmp->table_elem = NULL;
  60.     pushed = tmp->next;
  61.     delete tmp;
  62. }
  63.  
  64.  
  65. void LyXLex::printTable()
  66. {
  67.     lyxerr.print(LString("\nNumber of tags: ")+no_items);
  68.     for(int i=0; i<no_items; i++)
  69.         lyxerr.print(LString("table[")+i+
  70.                               "]:  tag: `"+table[i].tag+
  71.                               "'  code:"+table[i].code);
  72.     lyxerr.print(LString());
  73. }
  74.  
  75.  
  76. void LyXLex::printError(LString const & message)
  77. {
  78.     LString tmpmsg = message;
  79.     tmpmsg.subst("$$Token",GetString());
  80.     lyxerr.print("LyX: "+tmpmsg+" [around line "+lineno+" of file "
  81.               +MakeDisplayPath(name)+']');
  82. }
  83.  
  84.  
  85. bool LyXLex::setFile(LString const & filename)
  86. {
  87.         if (file) 
  88.         lyxerr.print("Error in LyXLex::setFile: file already set.");
  89.     file = fopen(filename.c_str(), "r");
  90.     name = filename;
  91.     owns_file = true;
  92.     lineno = 0;
  93.     return (file ? true : false);
  94. }
  95.  
  96.  
  97. void LyXLex::setFile(FILE *f)
  98. {
  99.         if (file) 
  100.         lyxerr.print("Error in LyXLex::setFile: file already set.");
  101.     file = f;
  102.     owns_file = false;
  103.     lineno = 0; // this is bogus if the file already has been read from
  104. }
  105.  
  106.  
  107. int LyXLex::lex()
  108. {
  109.     //NOTE: possible bug.
  110.    if (next() && status==LEX_TOKEN)
  111.        return search_kw(buff);
  112.    else
  113.        return status;
  114. }
  115.  
  116.  
  117. int LyXLex::GetInteger()
  118. {
  119.    if (buff[0]>' ')   
  120.        return atoi(buff);
  121.    else {
  122.     printError("Bad integer `$$Token'");
  123.     return -1;
  124.    }
  125. }
  126.  
  127.  
  128. float LyXLex::GetFloat()
  129. {
  130.    if (buff[0]>' ')   
  131.        return (float)strtod(buff, (char**)NULL);
  132.    else {
  133.     printError("Bad float `$$Token'");
  134.     return -1;
  135.    }
  136. }
  137.  
  138.  
  139. LString LyXLex::GetString() const
  140. {
  141.     return LString(buff);
  142. }
  143.  
  144.  
  145. // I would prefer to give a tag number instead of an explicit token
  146. // here, but it is not possible because Buffer::readLyXformat2 uses
  147. // explicit tokens (JMarc) 
  148. LString LyXLex::getLongString(LString const &endtoken)
  149. {
  150.     LString str, prefix;
  151.     bool firstline = true;
  152.  
  153.     while (IsOK()) {
  154.         if (!EatLine())
  155.             // blank line in the file being read
  156.             continue;
  157.         
  158.         LString const token = GetString().strip().frontStrip();
  159.         
  160.         lyxerr.debug("LongString: `"+GetString()+'\'', Error::PARSER);
  161.  
  162.         // We do a case independent comparison, like search_kw
  163.         // does.
  164.                 if (strcasecmp(token.c_str(), endtoken.c_str()) != 0) {
  165.             LString tmpstr = GetString();
  166.             if (firstline) {
  167.                 int i = 0;
  168.                 while(i < tmpstr.length()
  169.                       && tmpstr[i] == ' ') {
  170.                     i++;
  171.                     prefix += ' ';
  172.                 }
  173.                 firstline = false;
  174.                 lyxerr.debug("Prefix = `"+prefix+'\'',
  175.                           Error::PARSER); 
  176.             } 
  177.  
  178.             if (!prefix.empty() 
  179.                 && tmpstr.prefixIs(prefix.c_str())) {
  180.                 tmpstr.substring(prefix.length(), 
  181.                          tmpstr.length()-1);
  182.             }
  183.             str += tmpstr + '\n';
  184.                 }
  185.         else // token == endtoken
  186.             break;
  187.     }
  188.     if (!IsOK())
  189.         printError("Long string not ended by `" + endtoken + '\'');
  190.  
  191.     return str;
  192. }
  193.  
  194.  
  195. bool LyXLex::GetBool()
  196. {
  197.    if (strcmp(buff, "true") == 0)
  198.     return true;
  199.    else if (strcmp(buff, "false") != 0)
  200.     printError("Bad boolean `$$Token'. Use \"false\" or \"true\"");
  201.    return false;
  202. }
  203.  
  204.  
  205. bool LyXLex::EatLine()
  206. {
  207.     int i=0;
  208.     int c = '\0'; // getc() returns an int
  209.  
  210.     while (!feof(file) && c!='\n' && i!=(LEX_MAX_BUFF-1)) {
  211.         c = getc(file);
  212.         if (c != '\r')
  213.             buff[i++] = c;
  214.     }
  215.     if (i==(LEX_MAX_BUFF-1) && c !='\n') {
  216.            printError("Line too long");
  217.         c = '\n'; // Pretend we had an end of line
  218.         lineno--; // but don't increase line counter (netto effect)
  219.         i++; // and preserve last character read.
  220.     }
  221.     if (c=='\n') {
  222.         lineno++;
  223.         buff[--i] = '\0'; // i can never be 0 here, so no danger
  224.         status = LEX_DATA;
  225.         return true;
  226.     } else {
  227.         buff[i] = '\0';
  228.         return false;
  229.     }
  230. }
  231.  
  232.  
  233. int LyXLex::search_kw(char const *tag) const
  234. {
  235.     int m, k=0 , l= 0, r=no_items;
  236.  
  237.     while (l < r) {
  238.         m = (l+r)/2;
  239. #if DEBUG        
  240.         LString my_l;
  241.         my_l+="LyXLex::search_kw: elem " ;
  242.         my_l+= m; 
  243.         my_l+=" tag "; 
  244.         my_l+=table[m].tag;
  245.         my_l+=" search tag ";
  246.         my_l+= tag;
  247.  
  248.         lyxerr.debug(my_l,Error::PARSER);
  249. #endif
  250.                  //m,table[m].tag,tag);
  251.  
  252.         if (!table[m].tag)
  253.             k = strcasecmp(table[m].tag, tag);
  254.         if (k==0)
  255.             return table[m].code;
  256.         else
  257.             if (k<0) l = m+1; else r = m;
  258.     }
  259.     return -1;
  260. }
  261.  
  262.  
  263. bool LyXLex::next(bool esc)
  264. {
  265.  
  266.     if (!esc) {
  267.         int c; // getc() returns an int
  268.         int i;
  269.         
  270.         
  271.         status = 0;
  272.         while (!feof(file) && !status) { 
  273.             c = getc(file);
  274.             if (c=='#') {
  275.                 // Read rest of line (fast :-)
  276.                 fgets(buff, sizeof(buff), file);
  277.                 lineno++;
  278.                 continue;
  279.             }
  280.             
  281.             if (c=='\"') {
  282.                 i = -1;
  283.                 do {
  284.                     c = getc(file);
  285.                     if (c != '\r')
  286.                         buff[++i] = c;
  287.                 } while (c!='\"' && c!='\n' && !feof(file) &&
  288.                      i!=(LEX_MAX_BUFF-2));
  289.                 
  290.                 if (i==(LEX_MAX_BUFF-2)) {
  291.                     printError("Line too long");
  292.                     c = '\"'; // Pretend we got a "
  293.                     i++;
  294.                 }
  295.                 
  296.                 if (c!='\"') {
  297.                     printError("Missing quote");
  298.                     if (c=='\n')
  299.                         lineno++;
  300.                 }
  301.                 
  302.                 buff[i] = '\0';
  303.                 status = LEX_DATA;
  304.                 break; 
  305.             }
  306.             
  307.             if (c==',')
  308.                 continue;              /* Skip ','s */
  309.             
  310.             if (c > ' ' && !feof(file))  {
  311.                 i = 0;
  312.                 do {
  313.                     buff[i++] = c;
  314.                     c = getc(file);
  315.                 } while (c > ' ' && c != ',' && !feof(file) &&
  316.                      (i != LEX_MAX_BUFF-1) );
  317.                 if (i == LEX_MAX_BUFF-1) {
  318.                     printError("Line too long");
  319.                 }
  320.                 buff[i] = '\0';
  321.                 status = LEX_TOKEN;
  322.             }
  323.             
  324.             if (c=='\n')
  325.                 lineno++;
  326.             
  327.         }
  328.         if (status) return true;
  329.         
  330.         status = (feof(file)) ? LEX_FEOF: LEX_UNDEF;
  331.         buff[0] = '\0';
  332.         return false;
  333.     } else {
  334.         int c; // getc() returns an int
  335.         int i;
  336.         
  337.         
  338.         status = 0;
  339.         while (!feof(file) && !status) { 
  340.             c = getc(file);
  341.  
  342.             // skip ','s
  343.             if (c==',') continue;
  344.             
  345.             if (c=='\\') {
  346.                 // escape
  347.                 i = 0;
  348.                 do {
  349.                     if (c == '\\') {
  350.                         // escape the next char
  351.                         c = getc(file);
  352.                     }
  353.                     buff[i++] = c;
  354.                     c = getc(file);
  355.                 } while (c > ' ' && c != ',' && !feof(file) &&
  356.                      (i != LEX_MAX_BUFF-1) );
  357.                 if (i == LEX_MAX_BUFF-1) {
  358.                     printError("Line too long");
  359.                 }
  360.                 buff[i] = '\0';
  361.                 status = LEX_TOKEN;
  362.                 continue;
  363.             }
  364.             
  365.             if (c=='#') {
  366.                 // Read rest of line (fast :-)
  367.                 fgets(buff, sizeof(buff), file);
  368.                 lineno++;
  369.                 continue;
  370.             }
  371.  
  372.             // string
  373.             if (c=='\"') {
  374.                 i = -1;
  375.                 bool escaped = false;
  376.                 do {
  377.                     escaped = false;
  378.                     c = getc(file);
  379.                     if (c == '\r') continue;
  380.                     if (c == '\\') {
  381.                         // escape the next char
  382.                         c = getc(file);
  383.                         escaped = true;
  384.                     }
  385.                     buff[++i] = c;
  386.                 
  387.                     if (!escaped && c == '\"') break;
  388.                 } while (c!='\n' && !feof(file) &&
  389.                      i!=(LEX_MAX_BUFF-2));
  390.                 
  391.                 if (i==(LEX_MAX_BUFF-2)) {
  392.                     printError("Line too long");
  393.                     c = '\"'; // Pretend we got a "
  394.                     i++;
  395.                 }
  396.                 
  397.                 if (c!='\"') {
  398.                     printError("Missing quote");
  399.                     if (c=='\n')
  400.                         lineno++;
  401.                 }
  402.                 
  403.                 buff[i] = '\0';
  404.                 status = LEX_DATA;
  405.                 break; 
  406.             }
  407.             
  408.             if (c > ' ' && !feof(file))  {
  409.                 i = 0;
  410.                 do {
  411.                     if (c == '\\') {
  412.                         // escape the next char
  413.                         c = getc(file);
  414.                         //escaped = true;
  415.                     }
  416.                     buff[i++] = c;
  417.                     c = getc(file);
  418.                 } while (c > ' ' && c != ',' && !feof(file) &&
  419.                      (i != LEX_MAX_BUFF-1) );
  420.                 if (i == LEX_MAX_BUFF-1) {
  421.                     printError("Line too long");
  422.                 }
  423.                 buff[i] = '\0';
  424.                 status = LEX_TOKEN;
  425.             }
  426.  
  427.             // new line
  428.             if (c=='\n')
  429.                 lineno++;
  430.         }
  431.         
  432.         if (status) return true;
  433.         
  434.         status = (feof(file)) ? LEX_FEOF: LEX_UNDEF;
  435.         buff[0] = '\0';
  436.         return false;    
  437.     }
  438. }
  439.  
  440.  
  441. bool LyXLex::nextToken()
  442. {
  443.     int c; // getc() returns an int
  444.     int i;
  445.         
  446.         status = 0;
  447.     while (!feof(file) && !status) { 
  448.         c = getc(file);
  449.        
  450.         if (c >= ' ' && !feof(file))  {
  451.             i = 0;
  452.             if (c == '\\') { // first char == '\\'
  453.                 do {
  454.                     buff[i++] = c;
  455.                     c = getc(file);
  456.                 } while (c > ' ' && c != '\\' && !feof(file) &&
  457.                      i != (LEX_MAX_BUFF-1));
  458.             } else {
  459.                 do {
  460.                     buff[i++] = c;
  461.                     c = getc(file);
  462.                 } while (c >= ' ' && c != '\\' && !feof(file)
  463.                      && i != (LEX_MAX_BUFF-1));
  464.             }
  465.  
  466.             if (i == (LEX_MAX_BUFF-1)) {
  467.                 printError("Line too long");
  468.             }
  469.  
  470.             if (c == '\\') ungetc(c,file); // put it back
  471.             buff[i] = '\0';
  472.                 status = LEX_TOKEN;
  473.         }
  474.           
  475.         if (c=='\n')
  476.             lineno++;
  477.     
  478.     }
  479.         if (status)  return true;
  480.         
  481.         status = (feof(file)) ? LEX_FEOF: LEX_UNDEF;
  482.         buff[0] = '\0';
  483.         return false;
  484. }
  485.  
  486.  
  487. int LyXLex::FindToken(char const* string[])
  488. {  
  489.    int i = -1;
  490.    
  491.    if (next()) {
  492.       if (strcmp(buff, "default")) {
  493.      for (i=0; string[i][0] && strcmp(string[i], buff); i++);
  494.      if (!string[i][0]) {
  495.         printError("Unknown argument `$$Token'");
  496.         i = -1;
  497.      }
  498.       }  
  499.    } else
  500.      printError("file ended while scanning string token");
  501.    return i;
  502. }
  503.  
  504.  
  505. int LyXLex::CheckToken(char const* string[], int print_error)
  506. {  
  507.    int i = -1;
  508.    
  509.    if (strcmp(buff, "default")) {
  510.        for (i=0; string[i][0] && strcmp(string[i], buff); i++);
  511.        if (!string[i][0]) {
  512.            if (print_error)
  513.                printError("Unknown argument `$$Token'");
  514.            i = -1;
  515.        }
  516.    }
  517.    return i;
  518. }
  519.