• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kjs
 

kjs

  • kjs
lexer.cpp
1 // -*- c-basic-offset: 2 -*-
2 /*
3  * This file is part of the KDE libraries
4  * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB. If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <ctype.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 
33 #include "value.h"
34 #include "object.h"
35 #include "types.h"
36 #include "interpreter.h"
37 #include "nodes.h"
38 #include "lexer.h"
39 #include "identifier.h"
40 #include "lookup.h"
41 #include "internal.h"
42 #include "dtoa.h"
43 
44 // we can't specify the namespace in yacc's C output, so do it here
45 using namespace KJS;
46 
47 static Lexer *currLexer = 0;
48 
49 #ifndef KDE_USE_FINAL
50 #include "grammar.h"
51 #endif
52 
53 #include "lexer.lut.h"
54 
55 extern YYLTYPE yylloc; // global bison variable holding token info
56 
57 // a bridge for yacc from the C world to C++
58 int kjsyylex()
59 {
60  return Lexer::curr()->lex();
61 }
62 
63 Lexer::Lexer()
64  : yylineno(1),
65  size8(128), size16(128), restrKeyword(false),
66  convertNextIdentifier(false), stackToken(-1), lastToken(-1), pos(0),
67  code(0), length(0),
68 #ifndef KJS_PURE_ECMA
69  bol(true),
70 #endif
71  current(0), next1(0), next2(0), next3(0),
72  strings(0), numStrings(0), stringsCapacity(0),
73  identifiers(0), numIdentifiers(0), identifiersCapacity(0)
74 {
75  // allocate space for read buffers
76  buffer8 = new char[size8];
77  buffer16 = new UChar[size16];
78  currLexer = this;
79 }
80 
81 Lexer::~Lexer()
82 {
83  delete [] buffer8;
84  delete [] buffer16;
85 }
86 
87 Lexer *Lexer::curr()
88 {
89  if (!currLexer) {
90  // create singleton instance
91  currLexer = new Lexer();
92  }
93  return currLexer;
94 }
95 
96 #ifdef KJS_DEBUG_MEM
97 void Lexer::globalClear()
98 {
99  delete currLexer;
100  currLexer = 0L;
101 }
102 #endif
103 
104 void Lexer::setCode(const UChar *c, unsigned int len)
105 {
106  yylineno = 1;
107  restrKeyword = false;
108  delimited = false;
109  convertNextIdentifier = false;
110  stackToken = -1;
111  lastToken = -1;
112  foundBad = false;
113  pos = 0;
114  code = c;
115  length = len;
116  skipLF = false;
117  skipCR = false;
118 #ifndef KJS_PURE_ECMA
119  bol = true;
120 #endif
121 
122  // read first characters
123  current = (length > 0) ? code[0].uc : -1;
124  next1 = (length > 1) ? code[1].uc : -1;
125  next2 = (length > 2) ? code[2].uc : -1;
126  next3 = (length > 3) ? code[3].uc : -1;
127 }
128 
129 void Lexer::shift(unsigned int p)
130 {
131  while (p--) {
132  pos++;
133  current = next1;
134  next1 = next2;
135  next2 = next3;
136  next3 = (pos + 3 < length) ? code[pos+3].uc : -1;
137  }
138 }
139 
140 // called on each new line
141 void Lexer::nextLine()
142 {
143  yylineno++;
144 #ifndef KJS_PURE_ECMA
145  bol = true;
146 #endif
147 }
148 
149 void Lexer::setDone(State s)
150 {
151  state = s;
152  done = true;
153 }
154 
155 int Lexer::lex()
156 {
157  int token = 0;
158  state = Start;
159  unsigned short stringType = 0; // either single or double quotes
160  pos8 = pos16 = 0;
161  done = false;
162  terminator = false;
163  skipLF = false;
164  skipCR = false;
165 
166  // did we push a token on the stack previously ?
167  // (after an automatic semicolon insertion)
168  if (stackToken >= 0) {
169  setDone(Other);
170  token = stackToken;
171  stackToken = 0;
172  }
173 
174  while (!done) {
175  if (skipLF && current != '\n') // found \r but not \n afterwards
176  skipLF = false;
177  if (skipCR && current != '\r') // found \n but not \r afterwards
178  skipCR = false;
179  if (skipLF || skipCR) // found \r\n or \n\r -> eat the second one
180  {
181  skipLF = false;
182  skipCR = false;
183  shift(1);
184  }
185 
186  bool cr = (current == '\r');
187  bool lf = (current == '\n');
188  if (cr)
189  skipLF = true;
190  else if (lf)
191  skipCR = true;
192  bool isLineTerminator = cr || lf;
193 
194  switch (state) {
195  case Start:
196  if (isWhiteSpace(current)) {
197  // do nothing
198  } else if (current == '/' && next1 == '/') {
199  shift(1);
200  state = InSingleLineComment;
201  } else if (current == '/' && next1 == '*') {
202  shift(1);
203  state = InMultiLineComment;
204  } else if (current == -1) {
205  if (!terminator && !delimited) {
206  // automatic semicolon insertion if program incomplete
207  token = ';';
208  stackToken = 0;
209  setDone(Other);
210  } else
211  setDone(Eof);
212  } else if (isLineTerminator) {
213  nextLine();
214  terminator = true;
215  if (restrKeyword) {
216  token = ';';
217  setDone(Other);
218  }
219  } else if (current == '"' || current == '\'') {
220  state = InString;
221  stringType = current;
222  } else if (isIdentLetter(current)) {
223  record16(current);
224  state = InIdentifierOrKeyword;
225  } else if (current == '\\') {
226  state = InIdentifierUnicodeEscapeStart;
227  } else if (current == '0') {
228  record8(current);
229  state = InNum0;
230  } else if (isDecimalDigit(current)) {
231  record8(current);
232  state = InNum;
233  } else if (current == '.' && isDecimalDigit(next1)) {
234  record8(current);
235  state = InDecimal;
236 #ifndef KJS_PURE_ECMA
237  // <!-- marks the beginning of a line comment (for www usage)
238  } else if (current == '<' && next1 == '!' &&
239  next2 == '-' && next3 == '-') {
240  shift(3);
241  state = InSingleLineComment;
242  // same for -->
243  } else if (bol && current == '-' && next1 == '-' && next2 == '>') {
244  shift(2);
245  state = InSingleLineComment;
246 #endif
247  } else {
248  token = matchPunctuator(current, next1, next2, next3);
249  if (token != -1) {
250  setDone(Other);
251  } else {
252  // cerr << "encountered unknown character" << endl;
253  setDone(Bad);
254  }
255  }
256  break;
257  case InString:
258  if (current == stringType) {
259  shift(1);
260  setDone(String);
261  } else if (current == -1 || isLineTerminator) {
262  setDone(Bad);
263  } else if (current == '\\') {
264  state = InEscapeSequence;
265  } else {
266  record16(current);
267  }
268  break;
269  // Escape Sequences inside of strings
270  case InEscapeSequence:
271  if (isOctalDigit(current)) {
272  if (current >= '0' && current <= '3' &&
273  isOctalDigit(next1) && isOctalDigit(next2)) {
274  record16(convertOctal(current, next1, next2));
275  shift(2);
276  state = InString;
277  } else if (isOctalDigit(current) && isOctalDigit(next1)) {
278  record16(convertOctal('0', current, next1));
279  shift(1);
280  state = InString;
281  } else if (isOctalDigit(current)) {
282  record16(convertOctal('0', '0', current));
283  state = InString;
284  } else {
285  setDone(Bad);
286  }
287  } else if (current == 'x')
288  state = InHexEscape;
289  else if (current == 'u')
290  state = InUnicodeEscape;
291  else {
292  if (isLineTerminator)
293  nextLine();
294  record16(singleEscape(current));
295  state = InString;
296  }
297  break;
298  case InHexEscape:
299  if (isHexDigit(current) && isHexDigit(next1)) {
300  state = InString;
301  record16(convertHex(current, next1));
302  shift(1);
303  } else if (current == stringType) {
304  record16('x');
305  shift(1);
306  setDone(String);
307  } else {
308  record16('x');
309  record16(current);
310  state = InString;
311  }
312  break;
313  case InUnicodeEscape:
314  if (isHexDigit(current) && isHexDigit(next1) &&
315  isHexDigit(next2) && isHexDigit(next3)) {
316  record16(convertUnicode(current, next1, next2, next3));
317  shift(3);
318  state = InString;
319  } else if (current == stringType) {
320  record16('u');
321  shift(1);
322  setDone(String);
323  } else {
324  setDone(Bad);
325  }
326  break;
327  case InSingleLineComment:
328  if (isLineTerminator) {
329  nextLine();
330  terminator = true;
331  if (restrKeyword) {
332  token = ';';
333  setDone(Other);
334  } else
335  state = Start;
336  } else if (current == -1) {
337  setDone(Eof);
338  }
339  break;
340  case InMultiLineComment:
341  if (current == -1) {
342  setDone(Bad);
343  } else if (isLineTerminator) {
344  nextLine();
345  } else if (current == '*' && next1 == '/') {
346  state = Start;
347  shift(1);
348  }
349  break;
350  case InIdentifierOrKeyword:
351  case InIdentifier:
352  if (isIdentLetter(current) || isDecimalDigit(current))
353  record16(current);
354  else if (current == '\\')
355  state = InIdentifierUnicodeEscapeStart;
356  else
357  setDone(state == InIdentifierOrKeyword ? IdentifierOrKeyword : Identifier);
358  break;
359  case InNum0:
360  if (current == 'x' || current == 'X') {
361  record8(current);
362  state = InHex;
363  } else if (current == '.') {
364  record8(current);
365  state = InDecimal;
366  } else if (current == 'e' || current == 'E') {
367  record8(current);
368  state = InExponentIndicator;
369  } else if (isOctalDigit(current)) {
370  record8(current);
371  state = InOctal;
372  } else if (isDecimalDigit(current)) {
373  record8(current);
374  state = InDecimal;
375  } else {
376  setDone(Number);
377  }
378  break;
379  case InHex:
380  if (isHexDigit(current)) {
381  record8(current);
382  } else {
383  setDone(Hex);
384  }
385  break;
386  case InOctal:
387  if (isOctalDigit(current)) {
388  record8(current);
389  }
390  else if (isDecimalDigit(current)) {
391  record8(current);
392  state = InDecimal;
393  } else
394  setDone(Octal);
395  break;
396  case InNum:
397  if (isDecimalDigit(current)) {
398  record8(current);
399  } else if (current == '.') {
400  record8(current);
401  state = InDecimal;
402  } else if (current == 'e' || current == 'E') {
403  record8(current);
404  state = InExponentIndicator;
405  } else
406  setDone(Number);
407  break;
408  case InDecimal:
409  if (isDecimalDigit(current)) {
410  record8(current);
411  } else if (current == 'e' || current == 'E') {
412  record8(current);
413  state = InExponentIndicator;
414  } else
415  setDone(Number);
416  break;
417  case InExponentIndicator:
418  if (current == '+' || current == '-') {
419  record8(current);
420  } else if (isDecimalDigit(current)) {
421  record8(current);
422  state = InExponent;
423  } else
424  setDone(Bad);
425  break;
426  case InExponent:
427  if (isDecimalDigit(current)) {
428  record8(current);
429  } else
430  setDone(Number);
431  break;
432  case InIdentifierUnicodeEscapeStart:
433  if (current == 'u')
434  state = InIdentifierUnicodeEscape;
435  else
436  setDone(Bad);
437  break;
438  case InIdentifierUnicodeEscape:
439  if (isHexDigit(current) && isHexDigit(next1) && isHexDigit(next2) && isHexDigit(next3)) {
440  record16(convertUnicode(current, next1, next2, next3));
441  shift(3);
442  state = InIdentifier;
443  } else {
444  setDone(Bad);
445  }
446  break;
447  default:
448  assert(!"Unhandled state in switch statement");
449  }
450 
451  // move on to the next character
452  if (!done)
453  shift(1);
454 #ifndef KJS_PURE_ECMA
455  if (state != Start && state != InSingleLineComment)
456  bol = false;
457 #endif
458  }
459 
460  // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
461  if ((state == Number || state == Octal || state == Hex)
462  && isIdentLetter(current))
463  state = Bad;
464 
465  // terminate string
466  buffer8[pos8] = '\0';
467 
468 #ifdef KJS_DEBUG_LEX
469  fprintf(stderr, "line: %d ", lineNo());
470  fprintf(stderr, "yytext (%x): ", buffer8[0]);
471  fprintf(stderr, "%s ", buffer8);
472 #endif
473 
474  long double dval = 0;
475  if (state == Number) {
476  dval = kjs_strtod(buffer8, 0L);
477  } else if (state == Hex) { // scan hex numbers
478  dval = 0;
479  if (buffer8[0] == '0' && (buffer8[1] == 'x' || buffer8[1] == 'X')) {
480  for (const char *p = buffer8+2; *p; p++) {
481  if (!isHexDigit(*p)) {
482  dval = 0;
483  break;
484  }
485  dval = dval * 16 + convertHex(*p);
486  }
487  }
488  state = Number;
489  } else if (state == Octal) { // scan octal number
490  dval = 0;
491  if (buffer8[0] == '0') {
492  for (const char *p = buffer8+1; *p; p++) {
493  if (*p < '0' || *p > '7') {
494  dval = 0;
495  break;
496  }
497  dval = dval * 8 + *p - '0';
498  }
499  }
500  state = Number;
501  }
502 
503 #ifdef KJS_DEBUG_LEX
504  switch (state) {
505  case Eof:
506  printf("(EOF)\n");
507  break;
508  case Other:
509  printf("(Other)\n");
510  break;
511  case Identifier:
512  case IdentifierOrKeyword:
513  printf("(Identifier)/(Keyword)\n");
514  break;
515  case String:
516  printf("(String)\n");
517  break;
518  case Number:
519  printf("(Number)\n");
520  break;
521  default:
522  printf("(unknown)");
523  }
524 #endif
525 
526  if (state != Identifier && state != IdentifierOrKeyword &&
527  convertNextIdentifier)
528  convertNextIdentifier = false;
529 
530  restrKeyword = false;
531  delimited = false;
532  kjsyylloc.first_line = yylineno; // ???
533  kjsyylloc.last_line = yylineno;
534 
535  switch (state) {
536  case Eof:
537  token = 0;
538  break;
539  case Other:
540  if(token == '}' || token == ';') {
541  delimited = true;
542  }
543  break;
544  case IdentifierOrKeyword:
545  if ((token = Lookup::find(&mainTable, buffer16, pos16)) < 0) {
546  case Identifier:
547  // Lookup for keyword failed, means this is an identifier
548  // Apply anonymous-function hack below (convert the identifier)
549  if (convertNextIdentifier) {
550  convertNextIdentifier = false;
551 #ifdef KJS_VERBOSE
552  UString debugstr(buffer16, pos16); fprintf(stderr,"Anonymous function hack: eating identifier %s\n",debugstr.ascii());
553 #endif
554  token = FUNCEXPRIDENT;
555  } else {
556  token = IDENT;
557  }
558  /* TODO: close leak on parse error. same holds true for String */
559  kjsyylval.ident = makeIdentifier(buffer16, pos16);
560  break;
561  }
562 
563  convertNextIdentifier = false;
564  // Hack for "f = function somename() { ... }", too hard to get into the grammar
565  // Same for building an array with function pointers ( 'name', func1, 'name2', func2 )
566  // There are lots of other uses, we really have to get this into the grammar
567  if ( token == FUNCTION &&
568  ( lastToken == '=' || lastToken == ',' || lastToken == '(' ||
569  lastToken == ':' || lastToken == RETURN ) )
570  convertNextIdentifier = true;
571 
572  if (token == CONTINUE || token == BREAK ||
573  token == RETURN || token == THROW)
574  restrKeyword = true;
575  break;
576  case String:
577  kjsyylval.ustr = makeUString(buffer16, pos16);
578  token = STRING;
579  break;
580  case Number:
581  kjsyylval.dval = dval;
582  token = NUMBER;
583  break;
584  case Bad:
585  foundBad = true;
586  return -1;
587  default:
588  assert(!"unhandled numeration value in switch");
589  return -1;
590  }
591  lastToken = token;
592  return token;
593 }
594 
595 bool Lexer::isWhiteSpace(unsigned short c)
596 {
597  return (c == ' ' || c == '\t' ||
598  c == 0x0b || c == 0x0c || c == 0xa0);
599 }
600 
601 bool Lexer::isIdentLetter(unsigned short c)
602 {
603  // Allow any character in the Unicode categories
604  // Uppercase letter (Lu), Lowercase letter (Ll),
605  // Titlecase letter (Lt)", Modifier letter (Lm),
606  // Other letter (Lo), or Letter number (Nl).
607  // Also see: http://www.unicode.org/Public/UNIDATA/UnicodeData.txt */
608  return (c >= 'a' && c <= 'z' ||
609  c >= 'A' && c <= 'Z' ||
610  // A with grave - O with diaeresis
611  c >= 0x00c0 && c <= 0x00d6 ||
612  // O with stroke - o with diaeresis
613  c >= 0x00d8 && c <= 0x00f6 ||
614  // o with stroke - turned h with fishook and tail
615  c >= 0x00f8 && c <= 0x02af ||
616  // Greek etc. TODO: not precise
617  c >= 0x0388 && c <= 0x1ffc ||
618  c == '$' || c == '_');
619  /* TODO: use complete category table */
620 }
621 
622 bool Lexer::isDecimalDigit(unsigned short c)
623 {
624  return (c >= '0' && c <= '9');
625 }
626 
627 bool Lexer::isHexDigit(unsigned short c)
628 {
629  return (c >= '0' && c <= '9' ||
630  c >= 'a' && c <= 'f' ||
631  c >= 'A' && c <= 'F');
632 }
633 
634 bool Lexer::isOctalDigit(unsigned short c)
635 {
636  return (c >= '0' && c <= '7');
637 }
638 
639 int Lexer::matchPunctuator(unsigned short c1, unsigned short c2,
640  unsigned short c3, unsigned short c4)
641 {
642  if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
643  shift(4);
644  return URSHIFTEQUAL;
645  } else if (c1 == '=' && c2 == '=' && c3 == '=') {
646  shift(3);
647  return STREQ;
648  } else if (c1 == '!' && c2 == '=' && c3 == '=') {
649  shift(3);
650  return STRNEQ;
651  } else if (c1 == '>' && c2 == '>' && c3 == '>') {
652  shift(3);
653  return URSHIFT;
654  } else if (c1 == '<' && c2 == '<' && c3 == '=') {
655  shift(3);
656  return LSHIFTEQUAL;
657  } else if (c1 == '>' && c2 == '>' && c3 == '=') {
658  shift(3);
659  return RSHIFTEQUAL;
660  } else if (c1 == '<' && c2 == '=') {
661  shift(2);
662  return LE;
663  } else if (c1 == '>' && c2 == '=') {
664  shift(2);
665  return GE;
666  } else if (c1 == '!' && c2 == '=') {
667  shift(2);
668  return NE;
669  } else if (c1 == '+' && c2 == '+') {
670  shift(2);
671  if (terminator)
672  return AUTOPLUSPLUS;
673  else
674  return PLUSPLUS;
675  } else if (c1 == '-' && c2 == '-') {
676  shift(2);
677  if (terminator)
678  return AUTOMINUSMINUS;
679  else
680  return MINUSMINUS;
681  } else if (c1 == '=' && c2 == '=') {
682  shift(2);
683  return EQEQ;
684  } else if (c1 == '+' && c2 == '=') {
685  shift(2);
686  return PLUSEQUAL;
687  } else if (c1 == '-' && c2 == '=') {
688  shift(2);
689  return MINUSEQUAL;
690  } else if (c1 == '*' && c2 == '=') {
691  shift(2);
692  return MULTEQUAL;
693  } else if (c1 == '/' && c2 == '=') {
694  shift(2);
695  return DIVEQUAL;
696  } else if (c1 == '&' && c2 == '=') {
697  shift(2);
698  return ANDEQUAL;
699  } else if (c1 == '^' && c2 == '=') {
700  shift(2);
701  return XOREQUAL;
702  } else if (c1 == '%' && c2 == '=') {
703  shift(2);
704  return MODEQUAL;
705  } else if (c1 == '|' && c2 == '=') {
706  shift(2);
707  return OREQUAL;
708  } else if (c1 == '<' && c2 == '<') {
709  shift(2);
710  return LSHIFT;
711  } else if (c1 == '>' && c2 == '>') {
712  shift(2);
713  return RSHIFT;
714  } else if (c1 == '&' && c2 == '&') {
715  shift(2);
716  return AND;
717  } else if (c1 == '|' && c2 == '|') {
718  shift(2);
719  return OR;
720  }
721 
722  switch(c1) {
723  case '=':
724  case '>':
725  case '<':
726  case ',':
727  case '!':
728  case '~':
729  case '?':
730  case ':':
731  case '.':
732  case '+':
733  case '-':
734  case '*':
735  case '/':
736  case '&':
737  case '|':
738  case '^':
739  case '%':
740  case '(':
741  case ')':
742  case '{':
743  case '}':
744  case '[':
745  case ']':
746  case ';':
747  shift(1);
748  return static_cast<int>(c1);
749  default:
750  return -1;
751  }
752 }
753 
754 unsigned short Lexer::singleEscape(unsigned short c) const
755 {
756  switch(c) {
757  case 'b':
758  return 0x08;
759  case 't':
760  return 0x09;
761  case 'n':
762  return 0x0A;
763  case 'v':
764  return 0x0B;
765  case 'f':
766  return 0x0C;
767  case 'r':
768  return 0x0D;
769  case '"':
770  return 0x22;
771  case '\'':
772  return 0x27;
773  case '\\':
774  return 0x5C;
775  default:
776  return c;
777  }
778 }
779 
780 unsigned short Lexer::convertOctal(unsigned short c1, unsigned short c2,
781  unsigned short c3) const
782 {
783  return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
784 }
785 
786 unsigned char Lexer::convertHex(unsigned short c)
787 {
788  if (c >= '0' && c <= '9')
789  return (c - '0');
790  else if (c >= 'a' && c <= 'f')
791  return (c - 'a' + 10);
792  else
793  return (c - 'A' + 10);
794 }
795 
796 unsigned char Lexer::convertHex(unsigned short c1, unsigned short c2)
797 {
798  return ((convertHex(c1) << 4) + convertHex(c2));
799 }
800 
801 UChar Lexer::convertUnicode(unsigned short c1, unsigned short c2,
802  unsigned short c3, unsigned short c4)
803 {
804  return UChar((convertHex(c1) << 4) + convertHex(c2),
805  (convertHex(c3) << 4) + convertHex(c4));
806 }
807 
808 void Lexer::record8(unsigned short c)
809 {
810  assert(c <= 0xff);
811 
812  // enlarge buffer if full
813  if (pos8 >= size8 - 1) {
814  char *tmp = new char[2 * size8];
815  memcpy(tmp, buffer8, size8 * sizeof(char));
816  delete [] buffer8;
817  buffer8 = tmp;
818  size8 *= 2;
819  }
820 
821  buffer8[pos8++] = (char) c;
822 }
823 
824 void Lexer::record16(int c)
825 {
826  assert(c >= 0);
827  //assert(c <= USHRT_MAX);
828  record16(UChar(static_cast<unsigned short>(c)));
829 }
830 
831 void Lexer::record16(UChar c)
832 {
833  // enlarge buffer if full
834  if (pos16 >= size16 - 1) {
835  UChar *tmp = new UChar[2 * size16];
836  memcpy(tmp, buffer16, size16 * sizeof(UChar));
837  delete [] buffer16;
838  buffer16 = tmp;
839  size16 *= 2;
840  }
841 
842  buffer16[pos16++] = c;
843 }
844 
845 bool Lexer::scanRegExp()
846 {
847  pos16 = 0;
848  bool lastWasEscape = false;
849  bool inBrackets = false;
850 
851  while (1) {
852  if (current == '\r' || current == '\n' || current == -1)
853  return false;
854  else if (current != '/' || lastWasEscape == true || inBrackets == true)
855  {
856  // keep track of '[' and ']'
857  if ( !lastWasEscape ) {
858  if ( current == '[' && !inBrackets )
859  inBrackets = true;
860  if ( current == ']' && inBrackets )
861  inBrackets = false;
862  }
863  record16(current);
864  lastWasEscape =
865  !lastWasEscape && (current == '\\');
866  }
867  else { // end of regexp
868  pattern = UString(buffer16, pos16);
869  pos16 = 0;
870  shift(1);
871  break;
872  }
873  shift(1);
874  }
875 
876  while (isIdentLetter(current)) {
877  record16(current);
878  shift(1);
879  }
880  flags = UString(buffer16, pos16);
881 
882  return true;
883 }
884 
885 
886 void Lexer::doneParsing()
887 {
888  for (unsigned i = 0; i < numIdentifiers; i++) {
889  delete identifiers[i];
890  }
891  free(identifiers);
892  identifiers = 0;
893  numIdentifiers = 0;
894  identifiersCapacity = 0;
895 
896  for (unsigned i = 0; i < numStrings; i++) {
897  delete strings[i];
898  }
899  free(strings);
900  strings = 0;
901  numStrings = 0;
902  stringsCapacity = 0;
903 }
904 
905 const int initialCapacity = 64;
906 const int growthFactor = 2;
907 
908 Identifier *Lexer::makeIdentifier(UChar *buffer, unsigned int pos)
909 {
910  if (numIdentifiers == identifiersCapacity) {
911  identifiersCapacity = (identifiersCapacity == 0) ? initialCapacity : identifiersCapacity *growthFactor;
912  identifiers = (KJS::Identifier **)realloc(identifiers, sizeof(KJS::Identifier *) * identifiersCapacity);
913  }
914 
915  KJS::Identifier *identifier = new KJS::Identifier(buffer, pos);
916  identifiers[numIdentifiers++] = identifier;
917  return identifier;
918 }
919 
920 UString *Lexer::makeUString(UChar *buffer, unsigned int pos)
921 {
922  if (numStrings == stringsCapacity) {
923  stringsCapacity = (stringsCapacity == 0) ? initialCapacity : stringsCapacity *growthFactor;
924  strings = (UString **)realloc(strings, sizeof(UString *) * stringsCapacity);
925  }
926 
927  UString *string = new UString(buffer, pos);
928  strings[numStrings++] = string;
929  return string;
930 }
KJS::Number
Represents an primitive Number value.
Definition: value.h:368
KJS::UString
Unicode string class.
Definition: ustring.h:190
KJS::UChar
Unicode character.
Definition: ustring.h:52
KJS::String
Represents an primitive String value.
Definition: value.h:341
KJS
Definition: array_instance.h:28
KJS::Lookup::find
static int find(const struct HashTable *table, const Identifier &s)
Find an entry in the table, and return its value (i.e.
Definition: lookup.cpp:87
KJS::Identifier
Represents an Identifier for a Javascript object.
Definition: identifier.h:32

kjs

Skip menu "kjs"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kjs

Skip menu "kjs"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kjs by doxygen 1.8.11
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |