• 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
44using namespace KJS;
45
46static Lexer *currLexer = 0;
47
48#ifndef KDE_USE_FINAL
49#include "grammar.h"
50#endif
51
52#include "lexer.lut.h"
53
54extern YYLTYPE yylloc; // global bison variable holding token info
55
56// a bridge for yacc from the C world to C++
57int kjsyylex()
58{
59 return Lexer::curr()->lex();
60}
61
62Lexer::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
80Lexer::~Lexer()
81{
82 delete [] buffer8;
83 delete [] buffer16;
84}
85
86Lexer *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
96void Lexer::globalClear()
97{
98 delete currLexer;
99 currLexer = 0L;
100}
101#endif
102
103void 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
128void 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
140void Lexer::nextLine()
141{
142 yylineno++;
143#ifndef KJS_PURE_ECMA
144 bol = true;
145#endif
146}
147
148void Lexer::setDone(State s)
149{
150 state = s;
151 done = true;
152}
153
154int 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
594bool Lexer::isWhiteSpace(unsigned short c)
595{
596 return (c == ' ' || c == '\t' ||
597 c == 0x0b || c == 0x0c || c == 0xa0);
598}
599
600bool 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
621bool Lexer::isDecimalDigit(unsigned short c)
622{
623 return (c >= '0' && c <= '9');
624}
625
626bool Lexer::isHexDigit(unsigned short c)
627{
628 return (c >= '0' && c <= '9' ||
629 c >= 'a' && c <= 'f' ||
630 c >= 'A' && c <= 'F');
631}
632
633bool Lexer::isOctalDigit(unsigned short c)
634{
635 return (c >= '0' && c <= '7');
636}
637
638int 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
753unsigned 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
779unsigned 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
785unsigned 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
795unsigned char Lexer::convertHex(unsigned short c1, unsigned short c2)
796{
797 return ((convertHex(c1) << 4) + convertHex(c2));
798}
799
800UChar 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
807void 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
823void Lexer::record16(int c)
824{
825 assert(c >= 0);
826 //assert(c <= USHRT_MAX);
827 record16(UChar(static_cast<unsigned short>(c)));
828}
829
830void 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
844bool 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
885void 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
904const int initialCapacity = 64;
905const int growthFactor = 2;
906
907Identifier *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
919UString *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.4
This website is maintained by Timothy Pearson.