00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <spl/interp/JsLex.h>
00018 #include <spl/io/StringStream.h>
00019
00020 int JsLex::GetCh( )
00021 {
00022 int ch;
00023
00024 if (m_pushBack != -1)
00025 {
00026 ch = m_pushBack;
00027 m_pushBack = -1;
00028 }
00029 else
00030 {
00031 ch = m_text->ReadByte();
00032 }
00033
00034 if ('\n' == ch)
00035 {
00036 m_lineNo++;
00037 }
00038
00039 return ch;
00040 }
00041
00042 void JsLex::UnGetCh( const int ch )
00043 {
00044 ASSERT(m_pushBack == -1);
00045
00046 if ('\n' == ch)
00047 {
00048 m_lineNo--;
00049 }
00050 m_pushBack = ch;
00051 }
00052
00053 int JsLex::GetEscape( )
00054 {
00055 int ch = GetCh( );
00056 switch ( ch )
00057 {
00058 case 'n':
00059 ch = '\n';
00060 break;
00061 case 'r':
00062 ch = '\r';
00063 break;
00064 case 't':
00065 ch = '\t';
00066 break;
00067 case 'v':
00068 ch = '\v';
00069 break;
00070 case '\'':
00071 ch = '\'';
00072 break;
00073 case '\\':
00074 ch = '\\';
00075 break;
00076 default:
00077 ch = -1;
00078 }
00079 return ch;
00080 }
00081
00082 void JsLex::StripWS()
00083 {
00084 int ch = GetCh();
00085
00086 while ( IsWs(ch) )
00087 {
00088 ch = GetCh();
00089 }
00090 UnGetCh( ch );
00091 }
00092
00093 JsLex::JsLex()
00094 : m_text(),
00095 m_pushBack(-1),
00096 m_lineNo(1),
00097 m_lexum(),
00098 m_token(T_LEXERROR)
00099 {
00100 }
00101
00102 JsLex::JsLex(const String& text)
00103 : m_text(),
00104 m_lexum()
00105 {
00106 Init(text);
00107 }
00108
00109 JsLex::JsLex(spl::IStreamPtr stream)
00110 : m_text(),
00111 m_lexum()
00112 {
00113 Init(stream);
00114 }
00115
00116 JsLex::JsLex(const JsLex& lex)
00117 : m_text(lex.m_text),
00118 m_pushBack(lex.m_pushBack),
00119 m_lineNo(lex.m_lineNo),
00120 m_lexum(lex.m_lexum),
00121 m_token(lex.m_token)
00122 {
00123 }
00124
00125 JsLex::~JsLex()
00126 {
00127 }
00128
00129 JsLex& JsLex::operator =(const JsLex& lex)
00130 {
00131 m_text = lex.m_text;
00132 m_pushBack = lex.m_pushBack;
00133 m_lineNo = lex.m_lineNo;
00134 m_lexum = lex.m_lexum;
00135 m_token = lex.m_token;
00136
00137 return *this;
00138 }
00139
00140 void JsLex::Init(const String& text)
00141 {
00142 Init(StringStreamPtr(new StringStream(text)));
00143 }
00144
00145 void JsLex::Init(spl::IStreamPtr text)
00146 {
00147 m_text = text;
00148 m_pushBack = -1;
00149 m_lineNo = 1;
00150 m_lexum.Clear();
00151 m_token = T_LEXERROR;
00152
00153 int ch = GetCh();
00154 if ('#' == ch)
00155 {
00156
00157 while ( '\r' != ch && '\n' != ch )
00158 {
00159 ch = GetCh();
00160 }
00161 }
00162 UnGetCh( ch );
00163 }
00164
00165 JsLex::Token JsLex::Next()
00166 {
00167 m_lexum.Clear();
00168
00169 StripWS();
00170
00171 int ch = GetCh();
00172 if ( ch <= 0 )
00173 {
00174 m_token = T_JEOF;
00175 return m_token;
00176 }
00177 if ( isdigit( ch ) || ch == '.' )
00178 {
00179 Token toke = T_INT;
00180
00181 if ( ch == '.' )
00182 {
00183 ch = GetCh();
00184 if ( ! isdigit( ch ) )
00185 {
00186 UnGetCh( ch );
00187 m_token = T_DOT;
00188 return m_token;
00189 }
00190 toke = T_REAL;
00191 UnGetCh( ch );
00192 ch = '.';
00193 }
00194
00195
00196
00197
00198 while ( isdigit(ch) )
00199 {
00200 m_lexum.Append((char)ch);
00201 ch = GetCh();
00202 }
00203 if ( ch == 'x' )
00204 {
00205 if ( m_lexum.Length() != 1 )
00206 {
00207 m_lexum.Set("Invalid number format.");
00208 m_token = T_LEXERROR;
00209 return m_token;
00210 }
00211 if ( m_lexum.CharAt(0) != '0' )
00212 {
00213 m_lexum.Set("Invalid number format.");
00214 m_token = T_LEXERROR;
00215 return m_token;
00216 }
00217 m_lexum.Append((char)ch);
00218 ch = GetCh();
00219 while ( isdigit(ch) )
00220 {
00221 m_lexum.Append((char)ch);
00222 ch = GetCh();
00223 }
00224 UnGetCh(ch);
00225 m_token = T_HEX;
00226 return m_token;
00227 }
00228 if ( ch == '.' )
00229 {
00230 toke = T_REAL;
00231
00232 m_lexum.Append((char)ch);
00233 ch = GetCh();
00234 while ( isdigit(ch) )
00235 {
00236 m_lexum.Append((char)ch);
00237 ch = GetCh();
00238 }
00239 }
00240 if ( ch == 'e' || ch == 'E' )
00241 {
00242 toke = T_REAL;
00243 m_lexum.Append((char)ch);
00244 ch = GetCh();
00245 if ( ch == '+' || ch == '-' )
00246 {
00247 m_lexum.Append((char)ch);
00248 ch = GetCh();
00249 }
00250 while ( isdigit(ch) )
00251 {
00252 m_lexum.Append((char)ch);
00253 ch = GetCh();
00254 }
00255 }
00256 UnGetCh(ch);
00257 m_token = toke;
00258 return m_token;
00259 }
00260 else if ( isalpha( ch ) || ch == '_' )
00261 {
00262
00263
00264
00265 while ( isalnum( ch ) || ch == '_' )
00266 {
00267 m_lexum.Append((char)ch);
00268 ch = GetCh();
00269 }
00270 UnGetCh(ch);
00271 if ( m_lexum.Equals("var") )
00272 {
00273 m_token = T_VAR;
00274 return m_token;
00275 }
00276 if ( m_lexum.Equals("if") )
00277 {
00278 m_token = T_IF;
00279 return m_token;
00280 }
00281 if ( m_lexum.Equals("else") )
00282 {
00283 m_token = T_ELSE;
00284 return m_token;
00285 }
00286 if ( m_lexum.Equals("return") )
00287 {
00288 m_token = T_RETURN;
00289 return m_token;
00290 }
00291 if ( m_lexum.Equals("while") )
00292 {
00293 m_token = T_WHILE;
00294 return m_token;
00295 }
00296 if ( m_lexum.Equals("do") )
00297 {
00298 m_token = T_DO;
00299 return m_token;
00300 }
00301 if ( m_lexum.Equals("for") )
00302 {
00303 m_token = T_FOR;
00304 return m_token;
00305 }
00306 if ( m_lexum.Equals("break") )
00307 {
00308 m_token = T_BREAK;
00309 return m_token;
00310 }
00311 if ( m_lexum.Equals("static") )
00312 {
00313 m_token = T_STATIC;
00314 return m_token;
00315 }
00316 if ( m_lexum.Equals("class") )
00317 {
00318 m_token = T_CLASS;
00319 return m_token;
00320 }
00321 if ( m_lexum.Equals("public") )
00322 {
00323 m_token = T_PUBLIC;
00324 return m_token;
00325 }
00326 if ( m_lexum.Equals("private") )
00327 {
00328 m_token = T_PRIVATE;
00329 return m_token;
00330 }
00331 if ( m_lexum.Equals("protected") )
00332 {
00333 m_token = T_PROTECTED;
00334 return m_token;
00335 }
00336 if ( m_lexum.Equals("continue") )
00337 {
00338 m_token = T_CONTINUE;
00339 return m_token;
00340 }
00341 if ( m_lexum.Equals("switch") )
00342 {
00343 m_token = T_SWITCH;
00344 return m_token;
00345 }
00346 if ( m_lexum.Equals("case") )
00347 {
00348 m_token = T_CASE;
00349 return m_token;
00350 }
00351 if ( m_lexum.Equals("default") )
00352 {
00353 m_token = T_DEFAULT;
00354 return m_token;
00355 }
00356 if ( m_lexum.Equals("new") )
00357 {
00358 m_token = T_NEW;
00359 return m_token;
00360 }
00361 if ( m_lexum.Equals("delete") )
00362 {
00363 m_token = T_DELETE;
00364 return m_token;
00365 }
00366 if ( m_lexum.Equals("const") )
00367 {
00368 m_token = T_CONST;
00369 return m_token;
00370 }
00371 if ( m_lexum.Equals("null") )
00372 {
00373 m_token = T_JNULL;
00374 return m_token;
00375 }
00376 if ( m_lexum.Equals("try") )
00377 {
00378 m_token = T_TRY;
00379 return m_token;
00380 }
00381 if ( m_lexum.Equals("catch") )
00382 {
00383 m_token = T_CATCH;
00384 return m_token;
00385 }
00386 if ( m_lexum.Equals("finally") )
00387 {
00388 m_token = T_FINALLY;
00389 return m_token;
00390 }
00391 if ( m_lexum.Equals("throw") )
00392 {
00393 m_token = T_THROW;
00394 return m_token;
00395 }
00396 if ( m_lexum.Equals("true") )
00397 {
00398 m_token = T_YYTRUE;
00399 return m_token;
00400 }
00401 if ( m_lexum.Equals("false") )
00402 {
00403 m_token = T_YYFALSE;
00404 return m_token;
00405 }
00406 m_token = T_ID;
00407 return m_token;
00408 }
00409 switch ( ch )
00410 {
00411 case '\'':
00412
00413
00414
00415 ch = GetCh();
00416 if ( ch == '\\' )
00417 {
00418 ch = GetEscape();
00419 if ( -1 == ch )
00420 {
00421 m_lexum.Set("Unexpected escape");
00422 m_token = T_LEXERROR;
00423 return m_token;
00424 }
00425 }
00426 m_lexum.Append((char)ch);
00427 ch = GetCh();
00428 if ( ch != '\'' )
00429 {
00430 m_lexum.Set("Unterminated character");
00431 m_token = T_LEXERROR;
00432 return m_token;
00433 }
00434 m_token = T_CHAR;
00435 return m_token;
00436
00437 case '"':
00438
00439
00440
00441 while ( (ch = GetCh()) != -1 && ch != '"' )
00442 {
00443 if ( ch == '\\' )
00444 {
00445 ch = GetEscape();
00446 if ( -1 == ch )
00447 {
00448 m_lexum.Set("Unexpected escape");
00449 m_token = T_LEXERROR;
00450 return m_token;
00451 }
00452 }
00453 m_lexum.Append((char)ch);
00454 }
00455 if ( ch == -1 )
00456 {
00457 m_lexum.Set("Unterminated escape");
00458 m_token = T_LEXERROR;
00459 return m_token;
00460 }
00461 m_token = T_STRING;
00462 return m_token;
00463
00464 case '|':
00465
00466
00467
00468 ch = GetCh();
00469 if ( '|' == ch )
00470 {
00471 m_token = T_OR;
00472 return m_token;
00473 }
00474 if ( '=' == ch )
00475 {
00476 m_token = T_OREQ;
00477 return m_token;
00478 }
00479 UnGetCh(ch);
00480 m_token = T_PIPE;
00481 return m_token;
00482
00483 case '&':
00484
00485
00486
00487 ch = GetCh();
00488 if ( '&' == ch )
00489 {
00490 m_token = T_AND;
00491 return m_token;
00492 }
00493 if ( '=' == ch )
00494 {
00495 m_token = T_ANDEQ;
00496 return m_token;
00497 }
00498 UnGetCh(ch);
00499 m_token = T_AMPR;
00500 return m_token;
00501
00502 case '{':
00503 m_token = T_LBRACE;
00504 return m_token;
00505
00506 case '}':
00507 m_token = T_RBRACE;
00508 return m_token;
00509
00510 case '(':
00511 m_token = T_LPAR;
00512 return m_token;
00513
00514 case ')':
00515 m_token = T_RPAR;
00516 return m_token;
00517
00518 case '[':
00519 m_token = T_LBRAC;
00520 return m_token;
00521
00522 case ']':
00523 m_token = T_RBRAC;
00524 return m_token;
00525
00526 case '!':
00527 ch = GetCh();
00528 if ( '=' == ch )
00529 {
00530 m_token = T_ISNEQ;
00531 return m_token;
00532 }
00533 UnGetCh(ch);
00534 m_token = T_BANG;
00535 return m_token;
00536
00537 case '=':
00538 ch = GetCh();
00539 if ( '=' == ch )
00540 {
00541 m_token = T_ISEQUAL;
00542 return m_token;
00543 }
00544 UnGetCh(ch);
00545 m_token = T_ASSIGN;
00546 return m_token;
00547
00548 case '+':
00549 ch = GetCh();
00550 if ( '=' == ch )
00551 {
00552 m_token = T_PLUSEQ;
00553 return m_token;
00554 }
00555 if ( '+' == ch )
00556 {
00557 m_token = T_INC;
00558 return m_token;
00559 }
00560 UnGetCh( ch );
00561 m_token = T_PLUS;
00562 return m_token;
00563
00564 case '-':
00565 ch = GetCh();
00566 if ( '=' == ch )
00567 {
00568 m_token = T_MINUSEQ;
00569 return m_token;
00570 }
00571 if ( '-' == ch )
00572 {
00573 m_token = T_DEC;
00574 return m_token;
00575 }
00576 UnGetCh( ch );
00577 m_token = T_MINUS;
00578 return m_token;
00579
00580 case '*':
00581 ch = GetCh();
00582 if ( '=' == ch )
00583 {
00584 m_token = T_TIMESEQ;
00585 return m_token;
00586 }
00587 UnGetCh(ch);
00588 m_token = T_STAR;
00589 return m_token;
00590
00591 case '/':
00592 ch = GetCh();
00593 if ( '=' == ch )
00594 {
00595 m_token = T_DIVEQ;
00596 return m_token;
00597 }
00598 if ( '/' == ch )
00599 {
00600
00601
00602
00603 while ( ch != '\n' && ch > 0 )
00604 {
00605 ch = GetCh();
00606 }
00607 return Next();
00608 }
00609 if ( '*' == ch )
00610 {
00611
00612
00613
00614 int opencount = 1;
00615 while ( opencount > 0 && ch > 0 )
00616 {
00617 while ( ch != '*' && ch != '/' && ch > 0 )
00618 {
00619 ch = GetCh();
00620 }
00621 if ( ch == '*' )
00622 {
00623 ch = GetCh();
00624 if ( ch == '/' )
00625 {
00626 opencount--;
00627 }
00628 }
00629 if ( ch == '/' )
00630 {
00631 ch = GetCh();
00632 if ( ch == '*' )
00633 {
00634 opencount++;
00635 }
00636 }
00637 }
00638 return Next();
00639 }
00640 UnGetCh(ch);
00641 m_token = T_SLASH;
00642 return m_token;
00643
00644 case '%':
00645 ch = GetCh();
00646 if ( '=' == ch )
00647 {
00648 m_token = T_MODEQ;
00649 return m_token;
00650 }
00651 UnGetCh(ch);
00652 m_token = T_MOD;
00653 return m_token;
00654
00655 case '^':
00656 ch = GetCh();
00657 if ( '=' == ch )
00658 {
00659 m_token = T_XOREQ;
00660 return m_token;
00661 }
00662 UnGetCh(ch);
00663 m_token = T_XOR;
00664 return m_token;
00665
00666 case '~':
00667 ch = GetCh();
00668 if ( '=' == ch )
00669 {
00670 m_token = T_COMPEQ;
00671 return m_token;
00672 }
00673 UnGetCh(ch);
00674 m_token = T_COMP;
00675 return m_token;
00676
00677 case ':':
00678 ch = GetCh();
00679 if ( ':' == ch )
00680 {
00681 m_token = T_SCOPE;
00682 return m_token;
00683 }
00684 UnGetCh(ch);
00685 m_token = T_COLON;
00686 return m_token;
00687
00688 case ';':
00689 m_token = T_SEMI;
00690 return m_token;
00691
00692 case ',':
00693 m_token = T_COMMA;
00694 return m_token;
00695
00696 case '<':
00697 ch = GetCh();
00698 if ( '=' == ch )
00699 {
00700 m_token = T_LTEQ;
00701 return m_token;
00702 }
00703 else if ( '<' == ch )
00704 {
00705 m_token = T_LSHIFT;
00706 return m_token;
00707 }
00708 UnGetCh(ch);
00709 m_token = T_LT;
00710 return m_token;
00711
00712 case '>':
00713 ch = GetCh();
00714 if ( '=' == ch )
00715 {
00716 m_token = T_GTEQ;
00717 return m_token;
00718 }
00719 else if ( '>' == ch )
00720 {
00721 m_token = T_RSHIFT;
00722 return m_token;
00723 }
00724 UnGetCh(ch);
00725 m_token = T_GT;
00726 return m_token;
00727
00728 case -1:
00729 m_token = T_JEOF;
00730 return m_token;
00731
00732 default:
00733 m_lexum.Set("Internal lexer error");
00734 m_token = T_LEXERROR;
00735 return m_token;
00736 }
00737 #ifdef _WINDOWS
00738 m_token = T_LEXERROR;
00739 return m_token;
00740 #endif
00741 }
00742
00743 #if defined(DEBUG) || defined(_DEBUG)
00744 void JsLex::CheckMem() const
00745 {
00746 m_text.CheckMem();
00747 m_lexum.CheckMem();
00748 }
00749
00750 void JsLex::ValidateMem() const
00751 {
00752 m_text.ValidateMem();
00753 m_lexum.ValidateMem();
00754 }
00755 #endif