lexer.cpp Source File (kjs Library)

| # kjs Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# lexer.cpp

    00001 // -*- c-basic-offset: 2 -*-
    00002 /*
    00003  *  This file is part of the KDE libraries
    00004  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
    00005  *
    00006  *  This library is free software; you can redistribute it and/or
    00007  *  modify it under the terms of the GNU Lesser General Public
    00008  *  License as published by the Free Software Foundation; either
    00009  *  version 2 of the License, or (at your option) any later version.
    00010  *
    00011  *  This library is distributed in the hope that it will be useful,
    00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00014  *  Lesser General Public License for more details.
    00015  *
    00016  *  You should have received a copy of the GNU Lesser General Public License
    00017  *  along with this library; see the file COPYING.LIB.  If not, write to
    00018  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00019  *  Boston, MA 02111-1307, USA.
    00020  *
    00021  *  $Id: lexer.cpp,v 1.47 2002/11/19 22:47:27 faure Exp $
    00022  */
    00023
    00024 #ifdef HAVE_CONFIG_H
    00025 #include <config.h>
    00026 #endif
    00027
    00028 #include <ctype.h>
    00029 #include <stdlib.h>
    00030 #include <stdio.h>
    00031 #include <string.h>
    00032 #include <assert.h>
    00033
    00034 #include "value.h"
    00035 #include "object.h"
    00036 #include "types.h"
    00037 #include "interpreter.h"
    00038 #include "nodes.h"
    00039 #include "lexer.h"
    00040 #include "ustring.h"
    00041 #include "lookup.h"
    00042 #include "internal.h"
    00043
    00044 // we can't specify the namespace in yacc's C output, so do it here
    00045 using namespace KJS;
    00046
    00047 static Lexer *currLexer = 0;
    00048
    00049 #ifndef KDE_USE_FINAL
    00050 #include "grammar.h"
    00051 #endif
    00052
    00053 #include "lexer.lut.h"
    00054
    00055 extern YYLTYPE yylloc; // global bison variable holding token info
    00056
    00057 // a bridge for yacc from the C world to C++
    00058 int kjsyylex()
    00059 {
    00060   return Lexer::curr()->lex();
    00061 }
    00062
    00063 Lexer::Lexer()
    00064   : yylineno(1),
    00065     size8(128), size16(128), restrKeyword(false),
    00066     eatNextIdentifier(false), stackToken(-1), lastToken(-1), pos(0),
    00067     code(0), length(0),
    00068 #ifndef KJS_PURE_ECMA
    00069     bol(true),
    00070 #endif
    00071     current(0), next1(0), next2(0), next3(0)
    00072 {
    00073   // allocate space for read buffers
    00074   buffer8 = new char[size8];
    00075   buffer16 = new UChar[size16];
    00076   currLexer = this;
    00077
    00078 }
    00079
    00080 Lexer::~Lexer()
    00081 {
    00082   delete [] buffer8;
    00083   delete [] buffer16;
    00084 }
    00085
    00086 Lexer *Lexer::curr()
    00087 {
    00088   if (!currLexer) {
    00089     // create singleton instance
    00090     currLexer = new Lexer();
    00091   }
    00092   return currLexer;
    00093 }
    00094
    00095 #ifdef KJS_DEBUG_MEM
    00096 void Lexer::globalClear()
    00097 {
    00098   delete currLexer;
    00099   currLexer = 0L;
    00100 }
    00101 #endif
    00102
    00103 void Lexer::setCode(const UChar *c, unsigned int len)
    00104 {
    00105   yylineno = 1;
    00106   restrKeyword = false;
    00107   delimited = false;
    00108   eatNextIdentifier = false;
    00109   stackToken = -1;
    00110   lastToken = -1;
    00111   pos = 0;
    00112   code = c;
    00113   length = len;
    00114   skipLF = false;
    00115   skipCR = false;
    00116 #ifndef KJS_PURE_ECMA
    00117   bol = true;
    00118 #endif
    00119
    00120   // read first characters
    00121   current = (length > 0) ? code[0].unicode() : 0;
    00122   next1 = (length > 1) ? code[1].unicode() : 0;
    00123   next2 = (length > 2) ? code[2].unicode() : 0;
    00124   next3 = (length > 3) ? code[3].unicode() : 0;
    00125 }
    00126
    00127 void Lexer::shift(unsigned int p)
    00128 {
    00129   while (p--) {
    00130     pos++;
    00131     current = next1;
    00132     next1 = next2;
    00133     next2 = next3;
    00134     next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0;
    00135   }
    00136 }
    00137
    00138 // called on each new line
    00139 void Lexer::nextLine()
    00140 {
    00141   yylineno++;
    00142 #ifndef KJS_PURE_ECMA
    00143   bol = true;
    00144 #endif
    00145 }
    00146
    00147 void Lexer::setDone(State s)
    00148 {
    00149   state = s;
    00150   done = true;
    00151 }
    00152
    00153 int Lexer::lex()
    00154 {
    00155   int token = 0;
    00156   state = Start;
    00157   unsigned short stringType = 0; // either single or double quotes
    00158   pos8 = pos16 = 0;
    00159   done = false;
    00160   terminator = false;
    00161   skipLF = false;
    00162   skipCR = false;
    00163
    00164   // did we push a token on the stack previously ?
    00165   // (after an automatic semicolon insertion)
    00166   if (stackToken >= 0) {
    00167     setDone(Other);
    00168     token = stackToken;
    00169     stackToken = 0;
    00170   }
    00171
    00172   while (!done) {
    00173     if (skipLF && current != '\n') // found \r but not \n afterwards
    00174         skipLF = false;
    00175     if (skipCR && current != '\r') // found \n but not \r afterwards
    00176         skipCR = false;
    00177     if (skipLF || skipCR) // found \r\n or \n\r -> eat the second one
    00178     {
    00179         skipLF = false;
    00180         skipCR = false;
    00181         shift(1);
    00182     }
    00183
    00184     bool cr = (current == '\r');
    00185     bool lf = (current == '\n');
    00186     if (cr)
    00187       skipLF = true;
    00188     else if (lf)
    00189       skipCR = true;
    00190     bool isLineTerminator = cr || lf;
    00191
    00192     switch (state) {
    00193     case Start:
    00194       if (isWhiteSpace()) {
    00195         // do nothing
    00196       } else if (current == '/' && next1 == '/') {
    00197         shift(1);
    00198         state = InSingleLineComment;
    00199       } else if (current == '/' && next1 == '*') {
    00200         shift(1);
    00201         state = InMultiLineComment;
    00202       } else if (current == 0) {
    00203         if (!terminator && !delimited) {
    00204           // automatic semicolon insertion if program incomplete
    00205           token = ';';
    00206           stackToken = 0;
    00207           setDone(Other);
    00208         } else
    00209           setDone(Eof);
    00210       } else if (isLineTerminator) {
    00211         nextLine();
    00212         terminator = true;
    00213         if (restrKeyword) {
    00214           token = ';';
    00215           setDone(Other);
    00216         }
    00217       } else if (current == '"' || current == '\'') {
    00218         state = InString;
    00219         stringType = current;
    00220       } else if (isIdentLetter(current)) {
    00221         record16(current);
    00222         state = InIdentifier;
    00223       } else if (current == '0') {
    00224         record8(current);
    00225         state = InNum0;
    00226       } else if (isDecimalDigit(current)) {
    00227         record8(current);
    00228         state = InNum;
    00229       } else if (current == '.' && isDecimalDigit(next1)) {
    00230         record8(current);
    00231         state = InDecimal;
    00232 #ifndef KJS_PURE_ECMA
    00233         // <!-- marks the beginning of a line comment (for www usage)
    00234       } else if (current == '<' && next1 == '!' &&
    00235                  next2 == '-' && next3 == '-') {
    00236         shift(3);
    00237         state = InSingleLineComment;
    00238         // same for -->
    00239       } else if (bol && current == '-' && next1 == '-' &&  next2 == '>') {
    00240         shift(2);
    00241         state = InSingleLineComment;
    00242 #endif
    00243       } else {
    00244         token = matchPunctuator(current, next1, next2, next3);
    00245         if (token != -1) {
    00246           setDone(Other);
    00247         } else {
    00248           //      cerr << "encountered unknown character" << endl;
    00249           setDone(Bad);
    00250         }
    00251       }
    00252       break;
    00253     case InString:
    00254       if (current == stringType) {
    00255         shift(1);
    00256         setDone(String);
    00257       } else if (current == 0 || isLineTerminator) {
    00258         setDone(Bad);
    00259       } else if (current == '\\') {
    00260         state = InEscapeSequence;
    00261       } else {
    00262         record16(current);
    00263       }
    00264       break;
    00265     // Escape Sequences inside of strings
    00266     case InEscapeSequence:
    00267       if (isOctalDigit(current)) {
    00268         if (current >= '0' && current <= '3' &&
    00269             isOctalDigit(next1) && isOctalDigit(next2)) {
    00270           record16(convertOctal(current, next1, next2));
    00271           shift(2);
    00272           state = InString;
    00273         } else if (isOctalDigit(current) && isOctalDigit(next1)) {
    00274           record16(convertOctal('0', current, next1));
    00275           shift(1);
    00276           state = InString;
    00277         } else if (isOctalDigit(current)) {
    00278           record16(convertOctal('0', '0', current));
    00279           state = InString;
    00280         } else {
    00281           setDone(Bad);
    00282         }
    00283       } else if (current == 'x')
    00284         state = InHexEscape;
    00285       else if (current == 'u')
    00286         state = InUnicodeEscape;
    00287       else {
    00288         record16(singleEscape(current));
    00289         state = InString;
    00290       }
    00291       break;
    00292     case InHexEscape:
    00293       if (isHexDigit(current) && isHexDigit(next1)) {
    00294         state = InString;
    00295         record16(convertHex(current, next1));
    00296         shift(1);
    00297       } else if (current == stringType) {
    00298         record16('x');
    00299         shift(1);
    00300         setDone(String);
    00301       } else {
    00302         record16('x');
    00303         record16(current);
    00304         state = InString;
    00305       }
    00306       break;
    00307     case InUnicodeEscape:
    00308       if (isHexDigit(current) && isHexDigit(next1) &&
    00309           isHexDigit(next2) && isHexDigit(next3)) {
    00310         record16(convertUnicode(current, next1, next2, next3));
    00311         shift(3);
    00312         state = InString;
    00313       } else if (current == stringType) {
    00314         record16('u');
    00315         shift(1);
    00316         setDone(String);
    00317       } else {
    00318         setDone(Bad);
    00319       }
    00320       break;
    00321     case InSingleLineComment:
    00322       if (isLineTerminator) {
    00323         nextLine();
    00324         terminator = true;
    00325         if (restrKeyword) {
    00326           token = ';';
    00327           setDone(Other);
    00328         } else
    00329           state = Start;
    00330       } else if (current == 0) {
    00331         setDone(Eof);
    00332       }
    00333       break;
    00334     case InMultiLineComment:
    00335       if (current == 0) {
    00336         setDone(Bad);
    00337       } else if (isLineTerminator) {
    00338         nextLine();
    00339       } else if (current == '*' && next1 == '/') {
    00340         state = Start;
    00341         shift(1);
    00342       }
    00343       break;
    00344     case InIdentifier:
    00345       if (isIdentLetter(current) || isDecimalDigit(current)) {
    00346         record16(current);
    00347         break;
    00348       }
    00349       setDone(Identifier);
    00350       break;
    00351     case InNum0:
    00352       if (current == 'x' || current == 'X') {
    00353         record8(current);
    00354         state = InHex;
    00355       } else if (current == '.') {
    00356         record8(current);
    00357         state = InDecimal;
    00358       } else if (current == 'e' || current == 'E') {
    00359         record8(current);
    00360         state = InExponentIndicator;
    00361       } else if (isOctalDigit(current)) {
    00362         record8(current);
    00363         state = InOctal;
    00364       } else if (isDecimalDigit(current)) {
    00365         record8(current);
    00366         state = InDecimal;
    00367       } else {
    00368         setDone(Number);
    00369       }
    00370       break;
    00371     case InHex:
    00372       if (isHexDigit(current)) {
    00373         record8(current);
    00374       } else {
    00375         setDone(Hex);
    00376       }
    00377       break;
    00378     case InOctal:
    00379       if (isOctalDigit(current)) {
    00380         record8(current);
    00381       }
    00382       else if (isDecimalDigit(current)) {
    00383         record8(current);
    00384         state = InDecimal;
    00385       } else
    00386         setDone(Octal);
    00387       break;
    00388     case InNum:
    00389       if (isDecimalDigit(current)) {
    00390         record8(current);
    00391       } else if (current == '.') {
    00392         record8(current);
    00393         state = InDecimal;
    00394       } else if (current == 'e' || current == 'E') {
    00395         record8(current);
    00396         state = InExponentIndicator;
    00397       } else
    00398         setDone(Number);
    00399       break;
    00400     case InDecimal:
    00401       if (isDecimalDigit(current)) {
    00402         record8(current);
    00403       } else if (current == 'e' || current == 'E') {
    00404         record8(current);
    00405         state = InExponentIndicator;
    00406       } else
    00407         setDone(Number);
    00408       break;
    00409     case InExponentIndicator:
    00410       if (current == '+' || current == '-') {
    00411         record8(current);
    00412       } else if (isDecimalDigit(current)) {
    00413         record8(current);
    00414         state = InExponent;
    00415       } else
    00416         setDone(Bad);
    00417       break;
    00418     case InExponent:
    00419       if (isDecimalDigit(current)) {
    00420         record8(current);
    00421       } else
    00422         setDone(Number);
    00423       break;
    00424     default:
    00425       assert(!"Unhandled state in switch statement");
    00426     }
    00427
    00428     // move on to the next character
    00429     if (!done)
    00430       shift(1);
    00431 #ifndef KJS_PURE_ECMA
    00432     if (state != Start && state != InSingleLineComment)
    00433       bol = false;
    00434 #endif
    00435   }
    00436
    00437   // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
    00438   if ((state == Number || state == Octal || state == Hex)
    00439       && isIdentLetter(current))
    00440     state = Bad;
    00441
    00442   // terminate string
    00443   buffer8[pos8] = '\0';
    00444
    00445 #ifdef KJS_DEBUG_LEX
    00446   fprintf(stderr, "line: %d ", lineNo());
    00447   fprintf(stderr, "yytext (%x): ", buffer8[0]);
    00448   fprintf(stderr, "%s ", buffer8);
    00449 #endif
    00450
    00451   double dval = 0;
    00452   if (state == Number) {
    00453     dval = strtod(buffer8, 0L);
    00454   } else if (state == Hex) { // scan hex numbers
    00455     // TODO: support long unsigned int
    00456     unsigned int i;
    00457     sscanf(buffer8, "%x", &i);
    00458     dval = i;
    00459     state = Number;
    00460   } else if (state == Octal) {   // scan octal number
    00461     unsigned int ui;
    00462     sscanf(buffer8, "%o", &ui);
    00463     dval = ui;
    00464     state = Number;
    00465   }
    00466
    00467 #ifdef KJS_DEBUG_LEX
    00468   switch (state) {
    00469   case Eof:
    00470     printf("(EOF)\n");
    00471     break;
    00472   case Other:
    00473     printf("(Other)\n");
    00474     break;
    00475   case Identifier:
    00476     printf("(Identifier)/(Keyword)\n");
    00477     break;
    00478   case String:
    00479     printf("(String)\n");
    00480     break;
    00481   case Number:
    00482     printf("(Number)\n");
    00483     break;
    00484   default:
    00485     printf("(unknown)");
    00486   }
    00487 #endif
    00488
    00489   if (state != Identifier && eatNextIdentifier)
    00490     eatNextIdentifier = false;
    00491
    00492   restrKeyword = false;
    00493   delimited = false;
    00494   yylloc.first_line = yylineno; // ???
    00495   yylloc.last_line = yylineno;
    00496
    00497   switch (state) {
    00498   case Eof:
    00499     token = 0;
    00500     break;
    00501   case Other:
    00502     if(token == '}' || token == ';') {
    00503       delimited = true;
    00504     }
    00505     break;
    00506   case Identifier:
    00507     if ((token = Lookup::find(&mainTable, buffer16, pos16)) < 0) {
    00508       // Lookup for keyword failed, means this is an identifier
    00509       // Apply anonymous-function hack below (eat the identifier)
    00510       if (eatNextIdentifier) {
    00511         eatNextIdentifier = false;
    00512         UString debugstr(buffer16, pos16); fprintf(stderr,"Anonymous function hack: eating identifier %s\n",debugstr.ascii());
    00513         token = lex();
    00514         break;
    00515       }
    00516       /* TODO: close leak on parse error. same holds true for String */
    00517       kjsyylval.ustr = new UString(buffer16, pos16);
    00518       token = IDENT;
    00519       break;
    00520     }
    00521
    00522     eatNextIdentifier = false;
    00523     // Hack for "f = function somename() { ... }", too hard to get into the grammar
    00524     // Same for building an array with function pointers ( 'name', func1, 'name2', func2 )
    00525     // There are lots of other uses, we really have to get this into the grammar
    00526     if ( token == FUNCTION &&
    00527          ( lastToken == '=' || lastToken == ',' ) )
    00528             eatNextIdentifier = true;
    00529
    00530     if (token == CONTINUE || token == BREAK ||
    00531         token == RETURN || token == THROW)
    00532       restrKeyword = true;
    00533     break;
    00534   case String:
    00535     kjsyylval.ustr = new UString(buffer16, pos16);
    00536     token = STRING;
    00537     break;
    00538   case Number:
    00539     kjsyylval.dval = dval;
    00540     token = NUMBER;
    00541     break;
    00542   case Bad:
    00543     fprintf(stderr, "KJS: yylex: ERROR.\n");
    00544     return -1;
    00545   default:
    00546     assert(!"unhandled numeration value in switch");
    00547     return -1;
    00548   }
    00549   lastToken = token;
    00550   return token;
    00551 }
    00552
    00553 bool Lexer::isWhiteSpace() const
    00554 {
    00555   return (current == ' ' || current == '\t' ||
    00556           current == 0x0b || current == 0x0c);
    00557 }
    00558
    00559 bool Lexer::isIdentLetter(unsigned short c)
    00560 {
    00561   /* TODO: allow other legitimate unicode chars */
    00562   return (c >= 'a' && c <= 'z' ||
    00563           c >= 'A' && c <= 'Z' ||
    00564           c == '$' || c == '_');
    00565 }
    00566
    00567 bool Lexer::isDecimalDigit(unsigned short c)
    00568 {
    00569   return (c >= '0' && c <= '9');
    00570 }
    00571
    00572 bool Lexer::isHexDigit(unsigned short c) const
    00573 {
    00574   return (c >= '0' && c <= '9' ||
    00575           c >= 'a' && c <= 'f' ||
    00576           c >= 'A' && c <= 'F');
    00577 }
    00578
    00579 bool Lexer::isOctalDigit(unsigned short c) const
    00580 {
    00581   return (c >= '0' && c <= '7');
    00582 }
    00583
    00584 int Lexer::matchPunctuator(unsigned short c1, unsigned short c2,
    00585                               unsigned short c3, unsigned short c4)
    00586 {
    00587   if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
    00588     shift(4);
    00589     return URSHIFTEQUAL;
    00590   } else if (c1 == '=' && c2 == '=' && c3 == '=') {
    00591     shift(3);
    00592     return STREQ;
    00593   } else if (c1 == '!' && c2 == '=' && c3 == '=') {
    00594     shift(3);
    00595     return STRNEQ;
    00596    } else if (c1 == '>' && c2 == '>' && c3 == '>') {
    00597     shift(3);
    00598     return URSHIFT;
    00599   } else if (c1 == '<' && c2 == '<' && c3 == '=') {
    00600     shift(3);
    00601     return LSHIFTEQUAL;
    00602   } else if (c1 == '>' && c2 == '>' && c3 == '=') {
    00603     shift(3);
    00604     return RSHIFTEQUAL;
    00605   } else if (c1 == '<' && c2 == '=') {
    00606     shift(2);
    00607     return LE;
    00608   } else if (c1 == '>' && c2 == '=') {
    00609     shift(2);
    00610     return GE;
    00611   } else if (c1 == '!' && c2 == '=') {
    00612     shift(2);
    00613     return NE;
    00614   } else if (c1 == '+' && c2 == '+') {
    00615     shift(2);
    00616     if (terminator)
    00617       return AUTOPLUSPLUS;
    00618     else
    00619       return PLUSPLUS;
    00620   } else if (c1 == '-' && c2 == '-') {
    00621     shift(2);
    00622     if (terminator)
    00623       return AUTOMINUSMINUS;
    00624     else
    00625       return MINUSMINUS;
    00626   } else if (c1 == '=' && c2 == '=') {
    00627     shift(2);
    00628     return EQEQ;
    00629   } else if (c1 == '+' && c2 == '=') {
    00630     shift(2);
    00631     return PLUSEQUAL;
    00632   } else if (c1 == '-' && c2 == '=') {
    00633     shift(2);
    00634     return MINUSEQUAL;
    00635   } else if (c1 == '*' && c2 == '=') {
    00636     shift(2);
    00637     return MULTEQUAL;
    00638   } else if (c1 == '/' && c2 == '=') {
    00639     shift(2);
    00640     return DIVEQUAL;
    00641   } else if (c1 == '&' && c2 == '=') {
    00642     shift(2);
    00643     return ANDEQUAL;
    00644   } else if (c1 == '^' && c2 == '=') {
    00645     shift(2);
    00646     return XOREQUAL;
    00647   } else if (c1 == '%' && c2 == '=') {
    00648     shift(2);
    00649     return MODEQUAL;
    00650   } else if (c1 == '|' && c2 == '=') {
    00651     shift(2);
    00652     return OREQUAL;
    00653   } else if (c1 == '<' && c2 == '<') {
    00654     shift(2);
    00655     return LSHIFT;
    00656   } else if (c1 == '>' && c2 == '>') {
    00657     shift(2);
    00658     return RSHIFT;
    00659   } else if (c1 == '&' && c2 == '&') {
    00660     shift(2);
    00661     return AND;
    00662   } else if (c1 == '|' && c2 == '|') {
    00663     shift(2);
    00664     return OR;
    00665   }
    00666
    00667   switch(c1) {
    00668     case '=':
    00669     case '>':
    00670     case '<':
    00671     case ',':
    00672     case '!':
    00673     case '~':
    00674     case '?':
    00675     case ':':
    00676     case '.':
    00677     case '+':
    00678     case '-':
    00679     case '*':
    00680     case '/':
    00681     case '&':
    00682     case '|':
    00683     case '^':
    00684     case '%':
    00685     case '(':
    00686     case ')':
    00687     case '{':
    00688     case '}':
    00689     case '[':
    00690     case ']':
    00691     case ';':
    00692       shift(1);
    00693       return static_cast<int>(c1);
    00694     default:
    00695       return -1;
    00696   }
    00697 }
    00698
    00699 unsigned short Lexer::singleEscape(unsigned short c) const
    00700 {
    00701   switch(c) {
    00702   case 'b':
    00703     return 0x08;
    00704   case 't':
    00705     return 0x09;
    00706   case 'n':
    00707     return 0x0A;
    00708   case 'v':
    00709     return 0x0B;
    00710   case 'f':
    00711     return 0x0C;
    00712   case 'r':
    00713     return 0x0D;
    00714   case '"':
    00715     return 0x22;
    00716   case '\'':
    00717     return 0x27;
    00718   case '\\':
    00719     return 0x5C;
    00720   default:
    00721     return c;
    00722   }
    00723 }
    00724
    00725 unsigned short Lexer::convertOctal(unsigned short c1, unsigned short c2,
    00726                                       unsigned short c3) const
    00727 {
    00728   return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
    00729 }
    00730
    00731 unsigned char Lexer::convertHex(unsigned short c)
    00732 {
    00733   if (c >= '0' && c <= '9')
    00734     return (c - '0');
    00735   else if (c >= 'a' && c <= 'f')
    00736     return (c - 'a' + 10);
    00737   else
    00738     return (c - 'A' + 10);
    00739 }
    00740
    00741 unsigned char Lexer::convertHex(unsigned short c1, unsigned short c2)
    00742 {
    00743   return ((convertHex(c1) << 4) + convertHex(c2));
    00744 }
    00745
    00746 UChar Lexer::convertUnicode(unsigned short c1, unsigned short c2,
    00747                                      unsigned short c3, unsigned short c4)
    00748 {
    00749   return UChar((convertHex(c1) << 4) + convertHex(c2),
    00750                (convertHex(c3) << 4) + convertHex(c4));
    00751 }
    00752
    00753 void Lexer::record8(unsigned short c)
    00754 {
    00755   assert(c <= 0xff);
    00756
    00757   // enlarge buffer if full
    00758   if (pos8 >= size8 - 1) {
    00759     char *tmp = new char[2 * size8];
    00760     memcpy(tmp, buffer8, size8 * sizeof(char));
    00761     delete [] buffer8;
    00762     buffer8 = tmp;
    00763     size8 *= 2;
    00764   }
    00765
    00766   buffer8[pos8++] = (char) c;
    00767 }
    00768
    00769 void Lexer::record16(UChar c)
    00770 {
    00771   // enlarge buffer if full
    00772   if (pos16 >= size16 - 1) {
    00773     UChar *tmp = new UChar[2 * size16];
    00774     memcpy(tmp, buffer16, size16 * sizeof(UChar));
    00775     delete [] buffer16;
    00776     buffer16 = tmp;
    00777     size16 *= 2;
    00778   }
    00779
    00780   buffer16[pos16++] = c;
    00781 }
    00782
    00783 bool Lexer::scanRegExp()
    00784 {
    00785   pos16 = 0;
    00786   bool lastWasEscape = false;
    00787   bool inBrackets = false;
    00788
    00789   while (1) {
    00790     if (current == '\r' || current == '\n' || current == 0)
    00791       return false;
    00792     else if (current != '/' || lastWasEscape == true || inBrackets == true)
    00793     {
    00794         // keep track of '[' and ']'
    00795         if ( !lastWasEscape ) {
    00796           if ( current == '[' && !inBrackets )
    00797             inBrackets = true;
    00798           if ( current == ']' && inBrackets )
    00799             inBrackets = false;
    00800         }
    00801         record16(current);
    00802         lastWasEscape =
    00803             !lastWasEscape && (current == '\\');
    00804     }
    00805     else { // end of regexp
    00806       pattern = UString(buffer16, pos16);
    00807       pos16 = 0;
    00808       shift(1);
    00809       break;
    00810     }
    00811     shift(1);
    00812   }
    00813
    00814   while (isIdentLetter(current)) {
    00815     record16(current);
    00816     shift(1);
    00817   }
    00818   flags = UString(buffer16, pos16);
    00819
    00820   return true;
    00821 }

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:08:28 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001