src/Scanner.cpp
author David Anderson <dvander@alliedmods.net>
Wed Aug 01 22:32:59 2012 -0700 (2012-08-01)
changeset 145 e9d804821c48
parent 143 393f1b8ac8c3
child 146 dc7d3b7a918c
permissions -rw-r--r--
Introduced type semantics, completely replacing tag semantics.
danderson@92
     1
/* vim: set ts=4 sw=4 tw=99 et:
danderson@92
     2
 *
dvander@0
     3
 * Copyright (C) 2012 David Anderson
dvander@0
     4
 *
dvander@0
     5
 * This file is part of JITCraft.
dvander@0
     6
 *
dvander@0
     7
 * JITCraft is free software: you can redistribute it and/or modify it under
dvander@0
     8
 * the terms of the GNU General Public License as published by the Free
dvander@0
     9
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@0
    10
 * any later version.
dvander@0
    11
 * 
dvander@0
    12
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@0
    13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@0
    14
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@0
    15
 *
dvander@0
    16
 * You should have received a copy of the GNU General Public License along with
dvander@0
    17
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@0
    18
 */
dvander@0
    19
#include <assert.h>
dvander@0
    20
#include <ctype.h>
dvander@28
    21
#include <math.h>
danderson@92
    22
#include <limits.h>
danderson@92
    23
#include <string.h>
dvander@0
    24
#include "Scanner.h"
dvander@25
    25
#include "Utility.h"
dvander@0
    26
dvander@59
    27
using namespace ke;
dvander@0
    28
dvander@59
    29
const char *ke::TokenNames[] =
dvander@0
    30
{
dvander@0
    31
#define _(name, str) str,
dvander@0
    32
    TOKENMAP(_)
dvander@0
    33
#undef _
dvander@0
    34
    NULL
dvander@0
    35
};
dvander@0
    36
dvander@25
    37
Scanner::Scanner(CompileContext &cc, const char *stream, size_t length)
dvander@25
    38
  : cc_(cc),
dvander@25
    39
    stream_(stream),
dvander@0
    40
    length_(length),
dvander@0
    41
    pushed_(false),
dvander@0
    42
    saved_('\0'),
dvander@0
    43
    pos_(stream_)
dvander@0
    44
{
dvander@47
    45
    cur_.line = 1;
dvander@71
    46
    cur_.col = 1;
dvander@25
    47
    last_ = cur_;
dvander@0
    48
}
dvander@0
    49
dvander@0
    50
char
dvander@0
    51
Scanner::getChar()
dvander@0
    52
{
dvander@0
    53
    if (saved_ != '\0') {
dvander@0
    54
        char temp = saved_;
dvander@0
    55
        saved_ = '\0';
dvander@0
    56
        return temp;
dvander@0
    57
    }
dvander@0
    58
    if (pos_ >= stream_ + length_)
dvander@0
    59
        return '\0';
dvander@25
    60
    last_.col = cur_.col++;
dvander@0
    61
    return *pos_++;
dvander@0
    62
}
dvander@0
    63
dvander@0
    64
void
dvander@0
    65
Scanner::putChar(char c)
dvander@0
    66
{
dvander@0
    67
    assert(saved_ == '\0');
dvander@0
    68
    saved_ = c;
dvander@25
    69
    cur_.col = last_.col;
dvander@25
    70
}
dvander@25
    71
dvander@25
    72
void
dvander@25
    73
Scanner::calcNewLine(char c)
dvander@25
    74
{
dvander@25
    75
    cur_.line++;
dvander@71
    76
    cur_.col = 1;
dvander@25
    77
    last_ = cur_;
dvander@25
    78
dvander@25
    79
    char o;
dvander@25
    80
    if (c == '\r' && ((o = getChar()) != '\n'))
dvander@25
    81
        putChar(o);
dvander@0
    82
}
dvander@0
    83
dvander@0
    84
void
dvander@0
    85
Scanner::eatSingleLine()
dvander@0
    86
{
dvander@0
    87
    char c;
dvander@0
    88
    while ((c = getChar()) != '\0') {
dvander@25
    89
        if (c == '\n' || c == '\r') {
dvander@25
    90
            calcNewLine(c);
dvander@0
    91
            break;
dvander@25
    92
        }
dvander@0
    93
    }
dvander@0
    94
}
dvander@0
    95
dvander@0
    96
bool
dvander@0
    97
Scanner::eatComment()
dvander@0
    98
{
dvander@0
    99
    char c;
dvander@0
   100
dvander@0
   101
    while ((c = getChar()) != '\0') {
dvander@0
   102
        while (c == '*') {
dvander@0
   103
            c = getChar();
dvander@0
   104
            if (c == '\0')
dvander@0
   105
                return false;
dvander@0
   106
            if (c == '/')
dvander@0
   107
                return true;
dvander@0
   108
        }
dvander@25
   109
        if (c == '\r' || c == '\n')
dvander@25
   110
            calcNewLine(c);
dvander@0
   111
    }
dvander@0
   112
dvander@0
   113
    return false;
dvander@0
   114
}
dvander@0
   115
dvander@4
   116
static inline bool
dvander@4
   117
IsDigit(char c)
dvander@4
   118
{
dvander@4
   119
    return c >= '0' && c <= '9';
dvander@4
   120
}
dvander@4
   121
dvander@4
   122
// Based off the logic in sc2.c's ftoi()...
dvander@4
   123
double
dvander@4
   124
Scanner::ParseDouble(const char *string)
dvander@4
   125
{
dvander@4
   126
    const char *ptr = string;
dvander@4
   127
dvander@4
   128
    double number = 0.0;
dvander@4
   129
    while (IsDigit(*ptr)) {
dvander@4
   130
        number = (number * 10) + (*ptr - '0');
dvander@4
   131
        ptr++;
dvander@4
   132
    }
dvander@4
   133
dvander@4
   134
    assert(*ptr == '.');
dvander@4
   135
    ptr++;
dvander@4
   136
dvander@4
   137
    double fraction = 0.0;
dvander@4
   138
    double multiplier = 1.0;
dvander@4
   139
    while (IsDigit(*ptr)) {
dvander@4
   140
        fraction = (fraction * 10) + (*ptr - '0');
dvander@4
   141
        multiplier = multiplier / 10.0;
dvander@4
   142
        ptr++;
dvander@4
   143
    }
dvander@4
   144
dvander@4
   145
    number += fraction * multiplier;
dvander@4
   146
dvander@4
   147
    if (*ptr++ == 'e') {
dvander@4
   148
        int sign = 1;
dvander@4
   149
        if (*ptr == '-') {
dvander@4
   150
            sign = -1;
dvander@4
   151
            ptr++;
dvander@4
   152
        }
dvander@4
   153
dvander@4
   154
        int exponent = 0;
dvander@4
   155
        while (IsDigit(*ptr)) {
dvander@4
   156
            exponent = (exponent * 10) + (*ptr - '0');
dvander@4
   157
            ptr++;
dvander@4
   158
        }
dvander@4
   159
dvander@4
   160
        multiplier = pow(10.0, exponent * sign);
dvander@4
   161
        number *= multiplier;
dvander@4
   162
    }
dvander@4
   163
dvander@4
   164
    return number;
dvander@4
   165
}
dvander@4
   166
dvander@21
   167
static inline bool
dvander@21
   168
IsHexDigit(char c)
dvander@21
   169
{
dvander@21
   170
    return IsDigit(c) ||
dvander@21
   171
           (c >= 'a' && c <= 'f') ||
dvander@21
   172
           (c >= 'A' && c <= 'F');
dvander@21
   173
}
dvander@21
   174
dvander@21
   175
// Based on the logic for litchar() in sc2.c.
dvander@21
   176
int
dvander@21
   177
Scanner::readEscapeCode()
dvander@21
   178
{
dvander@21
   179
    char c = getChar();
dvander@21
   180
    if (c == '\\')
dvander@21
   181
        return c;
dvander@21
   182
dvander@21
   183
    switch (c) {
dvander@21
   184
      case 'a':
dvander@21
   185
        return '\a';
dvander@21
   186
      case 'b':
dvander@21
   187
        return '\b';
dvander@21
   188
      case 'e':
dvander@21
   189
        return 27;          // Apparently \e is non-standard.
dvander@21
   190
      case 'f':
dvander@21
   191
        return '\f';
dvander@21
   192
      case 'n':
dvander@21
   193
        return '\n';
dvander@21
   194
      case 'r':
dvander@21
   195
        return '\r';
dvander@21
   196
      case 't':
dvander@21
   197
        return '\t';
dvander@21
   198
      case '\v':
dvander@21
   199
        return '\v';
dvander@21
   200
dvander@21
   201
      case 'x':
dvander@21
   202
      {
dvander@21
   203
          unsigned digits = 0;
dvander@21
   204
          char r = 0;
dvander@21
   205
  
dvander@21
   206
          c = getChar();
dvander@21
   207
          while (IsHexDigit(c) && digits < 2) {
dvander@21
   208
              if (IsDigit(c))
dvander@21
   209
                  c = (c << 4) + (c - '0');
dvander@21
   210
              else
dvander@21
   211
                  c = (c << 4) + (tolower(c) - 'a' + 10);
dvander@21
   212
              digits++;
dvander@21
   213
              c = getChar();
dvander@21
   214
           }
dvander@21
   215
                
dvander@21
   216
          // Swallow a trailing ';'
dvander@21
   217
          if (c != ';')
dvander@21
   218
              putChar(c);
dvander@21
   219
  
dvander@21
   220
          return r;
dvander@21
   221
      }
dvander@21
   222
dvander@21
   223
      case '\'':
dvander@21
   224
      case '\"':
dvander@21
   225
      case '%':
dvander@21
   226
        return c;
dvander@21
   227
dvander@21
   228
      default:
dvander@21
   229
      {
dvander@21
   230
        if (IsDigit(c)) {
dvander@21
   231
            // \ddd
dvander@21
   232
            char r = 0;
dvander@21
   233
            while (IsDigit(c)) {
dvander@21
   234
                r = r * 10 + (c - '0');
dvander@21
   235
                c = getChar();
dvander@21
   236
            }
dvander@21
   237
dvander@21
   238
            // Swallow a trailing ;
dvander@21
   239
            if (c != ';')
dvander@21
   240
                putChar(c);
dvander@21
   241
dvander@21
   242
            return r;
dvander@21
   243
        }
dvander@25
   244
        cc_.reportError(begin(), Message_UnknownEscapeCode, c);
dvander@21
   245
        return INT_MAX;
dvander@21
   246
      }
dvander@21
   247
    }
dvander@21
   248
}
dvander@21
   249
dvander@21
   250
TokenKind
dvander@21
   251
Scanner::stringLiteral()
dvander@21
   252
{
dvander@21
   253
    literal_.clear();
dvander@21
   254
dvander@21
   255
    for (;;) {
dvander@21
   256
        char c = getChar();
dvander@21
   257
        if (c == '\"')
dvander@21
   258
            break;
dvander@21
   259
        if (c == '\r' || c == '\n' || c == '\0') {
dvander@25
   260
            cc_.reportError(begin(), Message_UnterminatedString);
dvander@21
   261
            return TOK_ERROR;
dvander@21
   262
        }
dvander@21
   263
        if (c == '\\') {
dvander@21
   264
            int code = readEscapeCode();
dvander@21
   265
            if (code == INT_MAX)
dvander@21
   266
                return TOK_ERROR;
dvander@21
   267
            c = char(code);
dvander@21
   268
        }
danderson@92
   269
        if (!literal_.append(c))
danderson@92
   270
            return TOK_ERROR;
dvander@21
   271
    }
dvander@21
   272
danderson@92
   273
    if (!literal_.append('\0'))
danderson@92
   274
        return TOK_ERROR;
danderson@92
   275
dvander@21
   276
    return TOK_STRING_LITERAL;
dvander@21
   277
}
dvander@21
   278
dvander@0
   279
TokenKind
dvander@4
   280
Scanner::numberLiteral(char first)
dvander@0
   281
{
danderson@92
   282
    literal_.clear();
danderson@92
   283
    if (!literal_.append(first))
danderson@92
   284
        return TOK_ERROR;
dvander@0
   285
dvander@4
   286
    char c;
dvander@0
   287
    for (;;) {
dvander@4
   288
        c = getChar();
dvander@4
   289
        if (!IsDigit(c))
dvander@0
   290
            break;
danderson@92
   291
        if (!literal_.append(c))
danderson@92
   292
            return TOK_ERROR;
dvander@0
   293
    }
dvander@0
   294
dvander@4
   295
    if (c != '.') {
dvander@4
   296
        putChar(c);
danderson@92
   297
        if (!literal_.append('\0'))
danderson@92
   298
            return TOK_ERROR;
dvander@4
   299
        return TOK_INTEGER_LITERAL;
dvander@4
   300
    }
danderson@92
   301
    if (!literal_.append(c))
danderson@92
   302
        return TOK_ERROR;
dvander@4
   303
dvander@4
   304
    c = getChar();
dvander@4
   305
    if (!IsDigit(c)) {
dvander@25
   306
        cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
dvander@4
   307
        return TOK_ERROR;
dvander@4
   308
    }
danderson@92
   309
    if (!literal_.append(c))
danderson@92
   310
        return TOK_ERROR;
dvander@4
   311
dvander@4
   312
    for (;;) {
dvander@4
   313
        c = getChar();
dvander@4
   314
        if (!IsDigit(c))
dvander@4
   315
            break;
danderson@92
   316
        if (!literal_.append(c))
danderson@92
   317
            return TOK_ERROR;
dvander@4
   318
    }
dvander@4
   319
dvander@4
   320
    if (c != 'e') {
dvander@4
   321
        putChar(c);
dvander@4
   322
    } else {
danderson@92
   323
        if (!literal_.append(c))
danderson@92
   324
            return TOK_ERROR;
dvander@4
   325
        c = getChar();
dvander@4
   326
        if (c == '-') {
danderson@92
   327
            if (!literal_.append(c))
danderson@92
   328
                return TOK_ERROR;
dvander@4
   329
            c = getChar();
dvander@4
   330
        }
dvander@4
   331
        if (!IsDigit(c)) {
dvander@25
   332
            cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
dvander@4
   333
            return TOK_ERROR;
dvander@4
   334
        }
danderson@92
   335
        if (!literal_.append(c))
danderson@92
   336
            return TOK_ERROR;
dvander@4
   337
        for (;;) {
dvander@4
   338
            c = getChar();
dvander@4
   339
            if (!IsDigit(c)) {
dvander@4
   340
                putChar(c);
dvander@4
   341
                break;
dvander@4
   342
            }
danderson@92
   343
            if (!literal_.append(c))
danderson@92
   344
                return TOK_ERROR;
dvander@4
   345
        }
dvander@4
   346
    }
dvander@4
   347
danderson@92
   348
    if (!literal_.append('\0'))
danderson@92
   349
        return TOK_ERROR;
danderson@92
   350
dvander@4
   351
    return TOK_FLOAT_LITERAL;
dvander@0
   352
}
dvander@0
   353
dvander@0
   354
TokenKind
dvander@0
   355
Scanner::identifier(char first)
dvander@0
   356
{
danderson@92
   357
    literal_.clear();
danderson@92
   358
    if (!literal_.append(first))
danderson@92
   359
        return TOK_ERROR;
dvander@0
   360
dvander@4
   361
    char c;
dvander@0
   362
    for (;;) {
dvander@4
   363
        c = getChar();
dvander@0
   364
        if (!isascii(c) || (!isalnum(c) && c != '_')) {
dvander@4
   365
            if (c != ':')
dvander@4
   366
                putChar(c);
dvander@0
   367
            break;
dvander@0
   368
        }
danderson@92
   369
        if (!literal_.append(c))
danderson@92
   370
            return TOK_ERROR;
dvander@0
   371
    }
dvander@133
   372
    
danderson@92
   373
    if (!literal_.append('\0'))
danderson@92
   374
        return TOK_ERROR;
danderson@92
   375
dvander@142
   376
    if (c != ':' && !strcmp(literal(), "_"))
dvander@133
   377
        return TOK_UNDERSCORE;
danderson@92
   378
    if (!strcmp(literal(),  "new"))
dvander@0
   379
        return TOK_NEW;
danderson@92
   380
    if (!strcmp(literal(),  "for"))
dvander@0
   381
        return TOK_FOR;
danderson@92
   382
    if (!strcmp(literal(),  "return"))
dvander@0
   383
        return TOK_RETURN;
danderson@92
   384
    if (!strcmp(literal(),  "if"))
dvander@0
   385
        return TOK_IF;
danderson@92
   386
    if (!strcmp(literal(),  "else"))
dvander@0
   387
        return TOK_ELSE;
danderson@92
   388
    if (!strcmp(literal(),  "enum"))
dvander@2
   389
        return TOK_ENUM;
danderson@92
   390
    if (!strcmp(literal(),  "while"))
dvander@9
   391
        return TOK_WHILE;
danderson@92
   392
    if (!strcmp(literal(),  "do"))
dvander@9
   393
        return TOK_DO;
danderson@92
   394
    if (!strcmp(literal(),  "break"))
dvander@10
   395
        return TOK_BREAK;
danderson@92
   396
    if (!strcmp(literal(),  "continue"))
dvander@10
   397
        return TOK_CONTINUE;
danderson@92
   398
    if (!strcmp(literal(),  "forward"))
dvander@63
   399
        return TOK_FORWARD;
danderson@92
   400
    if (!strcmp(literal(),  "public"))
dvander@63
   401
        return TOK_PUBLIC;
danderson@92
   402
    if (!strcmp(literal(),  "const"))
dvander@67
   403
        return TOK_CONST;
danderson@92
   404
    if (!strcmp(literal(),  "native"))
dvander@68
   405
        return TOK_NATIVE;
dvander@134
   406
    if (!strcmp(literal(),  "stock"))
dvander@134
   407
        return TOK_STOCK;
dvander@143
   408
    if (!strcmp(literal(),  "true"))
dvander@143
   409
        return TOK_TRUE;
dvander@143
   410
    if (!strcmp(literal(),  "false"))
dvander@143
   411
        return TOK_FALSE;
dvander@4
   412
    return (c == ':') ? TOK_LABEL : TOK_NAME;
dvander@0
   413
}
dvander@0
   414
dvander@0
   415
TokenKind
dvander@0
   416
Scanner::next()
dvander@0
   417
{
dvander@0
   418
    assert(!pushed_);
dvander@0
   419
dvander@0
   420
    for (;;) {
dvander@25
   421
        begin_ = cur_;
dvander@25
   422
dvander@0
   423
        char c = getChar();
dvander@0
   424
        switch (c) {
dvander@0
   425
          case '/':
dvander@0
   426
          {
dvander@0
   427
            c = getChar();
dvander@0
   428
            if (c == '/') {
dvander@0
   429
                eatSingleLine();
dvander@0
   430
                break;
dvander@0
   431
            }
dvander@0
   432
            if (c == '*') {
dvander@25
   433
                if (!eatComment()) {
dvander@25
   434
                    cc_.reportError(begin(), Message_UnterminatedComment);
dvander@0
   435
                    return TOK_ERROR;
dvander@25
   436
                }
dvander@0
   437
                break;
dvander@0
   438
            }
dvander@0
   439
            putChar(c);
dvander@0
   440
            return TOK_SLASH;
dvander@0
   441
          }
dvander@0
   442
dvander@25
   443
          case '\n':
dvander@25
   444
          case '\r':
dvander@25
   445
            calcNewLine(c);
dvander@25
   446
            break;
dvander@25
   447
dvander@0
   448
          case ';': return TOK_SEMICOLON;
dvander@0
   449
          case '{': return TOK_LBRACE;
dvander@0
   450
          case '}': return TOK_RBRACE;
dvander@0
   451
          case '(': return TOK_LPAREN;
dvander@0
   452
          case ')': return TOK_RPAREN;
dvander@0
   453
          case '[': return TOK_LBRACKET;
dvander@0
   454
          case ']': return TOK_RBRACKET;
dvander@78
   455
          case '~': return TOK_TILDE;
dvander@83
   456
          case '?': return TOK_QMARK;
dvander@83
   457
          case ':': return TOK_COLON;
dvander@2
   458
dvander@68
   459
          case '.':
dvander@68
   460
            c = getChar();
dvander@68
   461
            if (c == '.') {
dvander@68
   462
                c = getChar();
dvander@68
   463
                if (c == '.')
dvander@68
   464
                    return TOK_ELLIPSES;
dvander@68
   465
            }
dvander@68
   466
            cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
dvander@68
   467
            return TOK_ERROR;
dvander@68
   468
dvander@2
   469
          case '*':
dvander@2
   470
            c = getChar();
dvander@2
   471
            if (c == '=')
dvander@2
   472
                return TOK_ASSIGN_MUL;
dvander@2
   473
            putChar(c);
dvander@2
   474
            return TOK_STAR;
dvander@2
   475
dvander@2
   476
          case '+':
dvander@2
   477
            c = getChar();
dvander@2
   478
            if (c == '=')
dvander@2
   479
                return TOK_ASSIGN_ADD;
dvander@23
   480
            if (c == '+')
dvander@23
   481
                return TOK_INCREMENT;
dvander@2
   482
            putChar(c);
dvander@2
   483
            return TOK_PLUS;
dvander@2
   484
dvander@8
   485
          case '&':
dvander@22
   486
            c = getChar();
dvander@22
   487
            if (c == '=')
dvander@22
   488
                return TOK_ASSIGN_BITAND;
dvander@75
   489
            if (c == '&')
dvander@75
   490
                return TOK_AND;
dvander@22
   491
            putChar(c);
dvander@8
   492
            return TOK_BITAND;
dvander@8
   493
dvander@8
   494
          case '|':
dvander@22
   495
            c = getChar();
dvander@22
   496
            if (c == '=')
dvander@22
   497
                return TOK_ASSIGN_BITOR;
dvander@75
   498
            if (c == '|')
dvander@75
   499
                return TOK_OR;
dvander@22
   500
            putChar(c);
dvander@8
   501
            return TOK_BITOR;
dvander@8
   502
dvander@8
   503
          case '^':
dvander@22
   504
            c = getChar();
dvander@22
   505
            if (c == '=')
dvander@22
   506
                return TOK_ASSIGN_BITXOR;
dvander@22
   507
            putChar(c);
dvander@8
   508
            return TOK_BITXOR;
dvander@8
   509
dvander@82
   510
          case '%':
dvander@82
   511
            c = getChar();
dvander@82
   512
            if (c == '=')
dvander@82
   513
                return TOK_ASSIGN_MOD;
dvander@82
   514
            putChar(c);
dvander@82
   515
            return TOK_PERCENT;
dvander@82
   516
dvander@22
   517
          case '-':
dvander@22
   518
            c = getChar();
dvander@22
   519
            if (c == '=')
dvander@22
   520
                return TOK_ASSIGN_SUB;
dvander@23
   521
            if (c == '-')
dvander@23
   522
                return TOK_DECREMENT;
dvander@22
   523
            putChar(c);
dvander@22
   524
            return TOK_MINUS;
dvander@22
   525
dvander@0
   526
          case ',': return TOK_COMMA;
dvander@0
   527
          case '\0': return TOK_EOF;
dvander@0
   528
dvander@74
   529
          case '!':
dvander@74
   530
            c = getChar();
dvander@74
   531
            if (c == '=')
dvander@74
   532
                return TOK_NOTEQUALS;
dvander@74
   533
            putChar(c);
dvander@74
   534
            return TOK_NOT;
dvander@74
   535
dvander@0
   536
          case '=':
dvander@0
   537
            c = getChar();
dvander@0
   538
            if (c == '=')
dvander@0
   539
                return TOK_EQUALS;
dvander@0
   540
            putChar(c);
dvander@0
   541
            return TOK_ASSIGN;
dvander@0
   542
dvander@0
   543
          case '<':
dvander@0
   544
            c = getChar();
dvander@0
   545
            if (c == '=')
dvander@0
   546
                return TOK_LE;
dvander@2
   547
            if (c == '<') {
dvander@2
   548
                c = getChar();
dvander@2
   549
                if (c == '=')
dvander@2
   550
                    return TOK_ASSIGN_SHL;
dvander@138
   551
                putChar(c);
dvander@2
   552
                return TOK_SHL;
dvander@2
   553
            }
dvander@0
   554
            putChar(c);
dvander@0
   555
            return TOK_LT;
dvander@0
   556
dvander@0
   557
          case '>':
dvander@0
   558
            c = getChar();
dvander@0
   559
            if (c == '=')
dvander@0
   560
                return TOK_GE;
dvander@8
   561
            if (c == '>') {
dvander@8
   562
                c = getChar();
dvander@22
   563
                if (c == '>') {
dvander@22
   564
                    c = getChar();
dvander@22
   565
                    if (c == '=')
dvander@22
   566
                        return TOK_ASSIGN_USHR;
dvander@22
   567
                    putChar(c);
dvander@8
   568
                    return TOK_USHR;
dvander@22
   569
                }
dvander@8
   570
                return TOK_SHR;
dvander@8
   571
            }
dvander@0
   572
            putChar(c);
dvander@0
   573
            return TOK_GT;
dvander@0
   574
dvander@0
   575
          case ' ':
dvander@0
   576
          case '\t':
dvander@0
   577
          case '\f':
dvander@0
   578
            break;
dvander@0
   579
dvander@21
   580
          case '"':
dvander@21
   581
            return stringLiteral();
dvander@21
   582
dvander@0
   583
          default:
dvander@0
   584
            if (c >= '0' && c <= '9')
dvander@4
   585
                return numberLiteral(c);
dvander@0
   586
            if (c == '_' || (isascii(c) && isalpha(c)))
dvander@0
   587
                return identifier(c);
dvander@25
   588
            cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
dvander@0
   589
            return TOK_ERROR;
dvander@0
   590
        }
dvander@0
   591
    }
dvander@0
   592
}
dvander@0
   593
dvander@0
   594
TokenKind
dvander@0
   595
Scanner::scan()
dvander@0
   596
{
dvander@0
   597
    if (pushed_) {
dvander@0
   598
        pushed_ = false;
dvander@0
   599
        return lastToken_;
dvander@0
   600
    }
dvander@0
   601
    lastToken_ = next();
dvander@0
   602
    return lastToken_;
dvander@0
   603
}
dvander@0
   604
dvander@0
   605
TokenKind
dvander@0
   606
Scanner::peek()
dvander@0
   607
{
dvander@0
   608
    if (pushed_)
dvander@0
   609
        return lastToken_;
dvander@0
   610
    scan();
dvander@0
   611
    pushed_ = true;
dvander@0
   612
    return lastToken_;
dvander@0
   613
}