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

kjs

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

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
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kjs by doxygen 1.9.1
This website is maintained by Timothy Pearson.