src/compiler/Scanner.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jan 12 16:26:09 2013 -0800 (2013-01-12)
changeset 259 99ab8b19f0b9
parent 258 241d082d6d89
child 263 ba85a47ee414
permissions -rw-r--r--
Add |from x import names| support.
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@195
    24
#include "../Utility.h"
dvander@196
    25
#include "../Heap-inl.h"
dvander@254
    26
#include "../Handles-inl.h"
dvander@0
    27
#include "Scanner.h"
dvander@0
    28
dvander@59
    29
using namespace ke;
dvander@0
    30
dvander@59
    31
const char *ke::TokenNames[] =
dvander@0
    32
{
dvander@0
    33
#define _(name, str) str,
dvander@0
    34
    TOKENMAP(_)
dvander@0
    35
#undef _
dvander@0
    36
    NULL
dvander@0
    37
};
dvander@0
    38
dvander@25
    39
Scanner::Scanner(CompileContext &cc, const char *stream, size_t length)
dvander@25
    40
  : cc_(cc),
dvander@25
    41
    stream_(stream),
dvander@0
    42
    length_(length),
dvander@0
    43
    pushed_(false),
dvander@172
    44
    allowTags_(true),
dvander@0
    45
    saved_('\0'),
dvander@0
    46
    pos_(stream_)
dvander@0
    47
{
dvander@47
    48
    cur_.line = 1;
dvander@71
    49
    cur_.col = 1;
dvander@25
    50
    last_ = cur_;
dvander@0
    51
}
dvander@0
    52
dvander@0
    53
char
dvander@0
    54
Scanner::getChar()
dvander@0
    55
{
dvander@0
    56
    if (saved_ != '\0') {
dvander@0
    57
        char temp = saved_;
dvander@0
    58
        saved_ = '\0';
dvander@0
    59
        return temp;
dvander@0
    60
    }
dvander@0
    61
    if (pos_ >= stream_ + length_)
dvander@0
    62
        return '\0';
dvander@25
    63
    last_.col = cur_.col++;
dvander@0
    64
    return *pos_++;
dvander@0
    65
}
dvander@0
    66
dvander@0
    67
void
dvander@0
    68
Scanner::putChar(char c)
dvander@0
    69
{
dvander@0
    70
    assert(saved_ == '\0');
dvander@0
    71
    saved_ = c;
dvander@25
    72
    cur_.col = last_.col;
dvander@25
    73
}
dvander@25
    74
dvander@25
    75
void
dvander@25
    76
Scanner::calcNewLine(char c)
dvander@25
    77
{
dvander@25
    78
    cur_.line++;
dvander@71
    79
    cur_.col = 1;
dvander@25
    80
    last_ = cur_;
dvander@25
    81
dvander@25
    82
    char o;
dvander@25
    83
    if (c == '\r' && ((o = getChar()) != '\n'))
dvander@25
    84
        putChar(o);
dvander@0
    85
}
dvander@0
    86
dvander@0
    87
void
dvander@0
    88
Scanner::eatSingleLine()
dvander@0
    89
{
dvander@0
    90
    char c;
dvander@0
    91
    while ((c = getChar()) != '\0') {
dvander@25
    92
        if (c == '\n' || c == '\r') {
dvander@25
    93
            calcNewLine(c);
dvander@0
    94
            break;
dvander@25
    95
        }
dvander@0
    96
    }
dvander@0
    97
}
dvander@0
    98
dvander@0
    99
bool
dvander@0
   100
Scanner::eatComment()
dvander@0
   101
{
dvander@0
   102
    char c;
dvander@0
   103
dvander@0
   104
    while ((c = getChar()) != '\0') {
dvander@0
   105
        while (c == '*') {
dvander@0
   106
            c = getChar();
dvander@0
   107
            if (c == '\0')
dvander@0
   108
                return false;
dvander@0
   109
            if (c == '/')
dvander@0
   110
                return true;
dvander@0
   111
        }
dvander@25
   112
        if (c == '\r' || c == '\n')
dvander@25
   113
            calcNewLine(c);
dvander@0
   114
    }
dvander@0
   115
dvander@0
   116
    return false;
dvander@0
   117
}
dvander@0
   118
dvander@4
   119
static inline bool
dvander@4
   120
IsDigit(char c)
dvander@4
   121
{
dvander@4
   122
    return c >= '0' && c <= '9';
dvander@4
   123
}
dvander@4
   124
dvander@4
   125
// Based off the logic in sc2.c's ftoi()...
dvander@4
   126
double
dvander@4
   127
Scanner::ParseDouble(const char *string)
dvander@4
   128
{
dvander@4
   129
    const char *ptr = string;
dvander@4
   130
dvander@4
   131
    double number = 0.0;
dvander@4
   132
    while (IsDigit(*ptr)) {
dvander@4
   133
        number = (number * 10) + (*ptr - '0');
dvander@4
   134
        ptr++;
dvander@4
   135
    }
dvander@4
   136
dvander@4
   137
    assert(*ptr == '.');
dvander@4
   138
    ptr++;
dvander@4
   139
dvander@4
   140
    double fraction = 0.0;
dvander@4
   141
    double multiplier = 1.0;
dvander@4
   142
    while (IsDigit(*ptr)) {
dvander@4
   143
        fraction = (fraction * 10) + (*ptr - '0');
dvander@4
   144
        multiplier = multiplier / 10.0;
dvander@4
   145
        ptr++;
dvander@4
   146
    }
dvander@4
   147
dvander@4
   148
    number += fraction * multiplier;
dvander@4
   149
dvander@4
   150
    if (*ptr++ == 'e') {
dvander@4
   151
        int sign = 1;
dvander@4
   152
        if (*ptr == '-') {
dvander@4
   153
            sign = -1;
dvander@4
   154
            ptr++;
dvander@4
   155
        }
dvander@4
   156
dvander@4
   157
        int exponent = 0;
dvander@4
   158
        while (IsDigit(*ptr)) {
dvander@4
   159
            exponent = (exponent * 10) + (*ptr - '0');
dvander@4
   160
            ptr++;
dvander@4
   161
        }
dvander@4
   162
dvander@4
   163
        multiplier = pow(10.0, exponent * sign);
dvander@4
   164
        number *= multiplier;
dvander@4
   165
    }
dvander@4
   166
dvander@4
   167
    return number;
dvander@4
   168
}
dvander@4
   169
dvander@21
   170
static inline bool
dvander@21
   171
IsHexDigit(char c)
dvander@21
   172
{
dvander@21
   173
    return IsDigit(c) ||
dvander@21
   174
           (c >= 'a' && c <= 'f') ||
dvander@21
   175
           (c >= 'A' && c <= 'F');
dvander@21
   176
}
dvander@21
   177
dvander@21
   178
// Based on the logic for litchar() in sc2.c.
dvander@21
   179
int
dvander@21
   180
Scanner::readEscapeCode()
dvander@21
   181
{
dvander@21
   182
    char c = getChar();
dvander@21
   183
    if (c == '\\')
dvander@21
   184
        return c;
dvander@21
   185
dvander@21
   186
    switch (c) {
dvander@21
   187
      case 'a':
dvander@21
   188
        return '\a';
dvander@21
   189
      case 'b':
dvander@21
   190
        return '\b';
dvander@21
   191
      case 'e':
dvander@21
   192
        return 27;          // Apparently \e is non-standard.
dvander@21
   193
      case 'f':
dvander@21
   194
        return '\f';
dvander@21
   195
      case 'n':
dvander@21
   196
        return '\n';
dvander@21
   197
      case 'r':
dvander@21
   198
        return '\r';
dvander@21
   199
      case 't':
dvander@21
   200
        return '\t';
dvander@251
   201
      case 'v':
dvander@21
   202
        return '\v';
dvander@21
   203
dvander@21
   204
      case 'x':
dvander@21
   205
      {
dvander@21
   206
          unsigned digits = 0;
dvander@21
   207
          char r = 0;
dvander@21
   208
  
dvander@21
   209
          c = getChar();
dvander@21
   210
          while (IsHexDigit(c) && digits < 2) {
dvander@21
   211
              if (IsDigit(c))
dvander@21
   212
                  c = (c << 4) + (c - '0');
dvander@21
   213
              else
dvander@21
   214
                  c = (c << 4) + (tolower(c) - 'a' + 10);
dvander@21
   215
              digits++;
dvander@21
   216
              c = getChar();
dvander@21
   217
           }
dvander@21
   218
                
dvander@21
   219
          // Swallow a trailing ';'
dvander@21
   220
          if (c != ';')
dvander@21
   221
              putChar(c);
dvander@21
   222
  
dvander@21
   223
          return r;
dvander@21
   224
      }
dvander@21
   225
dvander@21
   226
      case '\'':
dvander@21
   227
      case '\"':
dvander@21
   228
      case '%':
dvander@21
   229
        return c;
dvander@21
   230
dvander@21
   231
      default:
dvander@21
   232
      {
dvander@21
   233
        if (IsDigit(c)) {
dvander@21
   234
            // \ddd
dvander@21
   235
            char r = 0;
dvander@21
   236
            while (IsDigit(c)) {
dvander@21
   237
                r = r * 10 + (c - '0');
dvander@21
   238
                c = getChar();
dvander@21
   239
            }
dvander@21
   240
dvander@21
   241
            // Swallow a trailing ;
dvander@21
   242
            if (c != ';')
dvander@21
   243
                putChar(c);
dvander@21
   244
dvander@21
   245
            return r;
dvander@21
   246
        }
dvander@25
   247
        cc_.reportError(begin(), Message_UnknownEscapeCode, c);
dvander@21
   248
        return INT_MAX;
dvander@21
   249
      }
dvander@21
   250
    }
dvander@21
   251
}
dvander@21
   252
dvander@21
   253
TokenKind
dvander@21
   254
Scanner::stringLiteral()
dvander@21
   255
{
dvander@21
   256
    literal_.clear();
dvander@21
   257
dvander@21
   258
    for (;;) {
dvander@21
   259
        char c = getChar();
dvander@21
   260
        if (c == '\"')
dvander@21
   261
            break;
dvander@21
   262
        if (c == '\r' || c == '\n' || c == '\0') {
dvander@25
   263
            cc_.reportError(begin(), Message_UnterminatedString);
dvander@21
   264
            return TOK_ERROR;
dvander@21
   265
        }
dvander@21
   266
        if (c == '\\') {
dvander@21
   267
            int code = readEscapeCode();
dvander@21
   268
            if (code == INT_MAX)
dvander@21
   269
                return TOK_ERROR;
dvander@21
   270
            c = char(code);
dvander@21
   271
        }
danderson@92
   272
        if (!literal_.append(c))
danderson@92
   273
            return TOK_ERROR;
dvander@21
   274
    }
dvander@21
   275
danderson@92
   276
    if (!literal_.append('\0'))
danderson@92
   277
        return TOK_ERROR;
danderson@92
   278
dvander@21
   279
    return TOK_STRING_LITERAL;
dvander@21
   280
}
dvander@21
   281
dvander@0
   282
TokenKind
dvander@176
   283
Scanner::hexLiteral()
dvander@176
   284
{
dvander@176
   285
    literal_.clear();
dvander@176
   286
dvander@176
   287
    char c;
dvander@176
   288
    for (;;) {
dvander@176
   289
        c = getChar();
dvander@176
   290
        if (!IsHexDigit(c))
dvander@176
   291
            break;
dvander@176
   292
        if (!literal_.append(c))
dvander@176
   293
            return TOK_ERROR;
dvander@176
   294
    }
dvander@176
   295
dvander@176
   296
    putChar(c);
dvander@176
   297
dvander@176
   298
    if (!literal_.append('\0'))
dvander@176
   299
        return TOK_ERROR;
dvander@176
   300
    return TOK_HEX_LITERAL;
dvander@176
   301
}
dvander@176
   302
dvander@176
   303
TokenKind
dvander@4
   304
Scanner::numberLiteral(char first)
dvander@0
   305
{
danderson@92
   306
    literal_.clear();
danderson@92
   307
    if (!literal_.append(first))
danderson@92
   308
        return TOK_ERROR;
dvander@0
   309
dvander@4
   310
    char c;
dvander@0
   311
    for (;;) {
dvander@4
   312
        c = getChar();
dvander@4
   313
        if (!IsDigit(c))
dvander@0
   314
            break;
danderson@92
   315
        if (!literal_.append(c))
danderson@92
   316
            return TOK_ERROR;
dvander@0
   317
    }
dvander@0
   318
dvander@176
   319
    // Detect a hexadecimal string.
dvander@176
   320
    if (literal_.length() == 1 &&
dvander@176
   321
        literal_[0] == '0' &&
dvander@176
   322
        (c == 'x' || c == 'X'))
dvander@176
   323
    {
dvander@176
   324
        return hexLiteral();
dvander@176
   325
    }
dvander@176
   326
dvander@4
   327
    if (c != '.') {
dvander@4
   328
        putChar(c);
danderson@92
   329
        if (!literal_.append('\0'))
danderson@92
   330
            return TOK_ERROR;
dvander@4
   331
        return TOK_INTEGER_LITERAL;
dvander@4
   332
    }
danderson@92
   333
    if (!literal_.append(c))
danderson@92
   334
        return TOK_ERROR;
dvander@4
   335
dvander@4
   336
    c = getChar();
dvander@4
   337
    if (!IsDigit(c)) {
dvander@25
   338
        cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
dvander@4
   339
        return TOK_ERROR;
dvander@4
   340
    }
danderson@92
   341
    if (!literal_.append(c))
danderson@92
   342
        return TOK_ERROR;
dvander@4
   343
dvander@4
   344
    for (;;) {
dvander@4
   345
        c = getChar();
dvander@4
   346
        if (!IsDigit(c))
dvander@4
   347
            break;
danderson@92
   348
        if (!literal_.append(c))
danderson@92
   349
            return TOK_ERROR;
dvander@4
   350
    }
dvander@4
   351
dvander@4
   352
    if (c != 'e') {
dvander@4
   353
        putChar(c);
dvander@4
   354
    } else {
danderson@92
   355
        if (!literal_.append(c))
danderson@92
   356
            return TOK_ERROR;
dvander@4
   357
        c = getChar();
dvander@4
   358
        if (c == '-') {
danderson@92
   359
            if (!literal_.append(c))
danderson@92
   360
                return TOK_ERROR;
dvander@4
   361
            c = getChar();
dvander@4
   362
        }
dvander@4
   363
        if (!IsDigit(c)) {
dvander@25
   364
            cc_.reportError(begin(), Message_ExpectedDigitForFloat, c);
dvander@4
   365
            return TOK_ERROR;
dvander@4
   366
        }
danderson@92
   367
        if (!literal_.append(c))
danderson@92
   368
            return TOK_ERROR;
dvander@4
   369
        for (;;) {
dvander@4
   370
            c = getChar();
dvander@4
   371
            if (!IsDigit(c)) {
dvander@4
   372
                putChar(c);
dvander@4
   373
                break;
dvander@4
   374
            }
danderson@92
   375
            if (!literal_.append(c))
danderson@92
   376
                return TOK_ERROR;
dvander@4
   377
        }
dvander@4
   378
    }
dvander@4
   379
danderson@92
   380
    if (!literal_.append('\0'))
danderson@92
   381
        return TOK_ERROR;
danderson@92
   382
dvander@4
   383
    return TOK_FLOAT_LITERAL;
dvander@0
   384
}
dvander@0
   385
dvander@171
   386
static inline TokenKind
dvander@171
   387
FindIdentifier(const char *str)
dvander@171
   388
{
dvander@171
   389
    if (!strcmp(str,  "new"))
dvander@171
   390
        return TOK_NEW;
dvander@171
   391
    if (!strcmp(str,  "for"))
dvander@171
   392
        return TOK_FOR;
dvander@171
   393
    if (!strcmp(str,  "return"))
dvander@171
   394
        return TOK_RETURN;
dvander@171
   395
    if (!strcmp(str,  "if"))
dvander@171
   396
        return TOK_IF;
dvander@171
   397
    if (!strcmp(str,  "else"))
dvander@171
   398
        return TOK_ELSE;
dvander@171
   399
    if (!strcmp(str,  "enum"))
dvander@171
   400
        return TOK_ENUM;
dvander@171
   401
    if (!strcmp(str,  "while"))
dvander@171
   402
        return TOK_WHILE;
dvander@171
   403
    if (!strcmp(str,  "do"))
dvander@171
   404
        return TOK_DO;
dvander@171
   405
    if (!strcmp(str,  "break"))
dvander@171
   406
        return TOK_BREAK;
dvander@171
   407
    if (!strcmp(str,  "continue"))
dvander@171
   408
        return TOK_CONTINUE;
dvander@171
   409
    if (!strcmp(str,  "forward"))
dvander@171
   410
        return TOK_FORWARD;
dvander@171
   411
    if (!strcmp(str,  "public"))
dvander@171
   412
        return TOK_PUBLIC;
dvander@171
   413
    if (!strcmp(str,  "const"))
dvander@171
   414
        return TOK_CONST;
dvander@171
   415
    if (!strcmp(str,  "native"))
dvander@171
   416
        return TOK_NATIVE;
dvander@171
   417
    if (!strcmp(str,  "stock"))
dvander@171
   418
        return TOK_STOCK;
dvander@171
   419
    if (!strcmp(str,  "true"))
dvander@171
   420
        return TOK_TRUE;
dvander@171
   421
    if (!strcmp(str,  "false"))
dvander@171
   422
        return TOK_FALSE;
dvander@171
   423
    if (!strcmp(str,  "struct"))
dvander@171
   424
        return TOK_STRUCT;
dvander@171
   425
    if (!strcmp(str,  "switch"))
dvander@171
   426
        return TOK_SWITCH;
dvander@171
   427
    if (!strcmp(str,  "case"))
dvander@171
   428
        return TOK_CASE;
dvander@171
   429
    if (!strcmp(str,  "default"))
dvander@171
   430
        return TOK_DEFAULT;
dvander@174
   431
    if (!strcmp(str,  "typedef"))
dvander@174
   432
        return TOK_TYPEDEF;
dvander@174
   433
    if (!strcmp(str,  "void"))
dvander@174
   434
        return TOK_VOID;
dvander@174
   435
    if (!strcmp(str,  "int"))
dvander@174
   436
        return TOK_INT;
dvander@194
   437
    if (!strcmp(str,  "sizeof"))
dvander@194
   438
        return TOK_SIZEOF;
dvander@195
   439
    if (!strcmp(str,  "import"))
dvander@195
   440
        return TOK_IMPORT;
dvander@258
   441
    if (!strcmp(str,  "from"))
dvander@258
   442
        return TOK_FROM;
dvander@171
   443
    return TOK_NONE;
dvander@171
   444
}
dvander@171
   445
dvander@0
   446
TokenKind
dvander@0
   447
Scanner::identifier(char first)
dvander@0
   448
{
danderson@92
   449
    literal_.clear();
danderson@92
   450
    if (!literal_.append(first))
danderson@92
   451
        return TOK_ERROR;
dvander@0
   452
dvander@4
   453
    char c;
dvander@0
   454
    for (;;) {
dvander@4
   455
        c = getChar();
dvander@171
   456
        if (!isascii(c) || (!isalnum(c) && c != '_'))
dvander@0
   457
            break;
danderson@92
   458
        if (!literal_.append(c))
danderson@92
   459
            return TOK_ERROR;
dvander@0
   460
    }
dvander@133
   461
    
danderson@92
   462
    if (!literal_.append('\0'))
danderson@92
   463
        return TOK_ERROR;
danderson@92
   464
dvander@171
   465
    // Most keywords do not act as labels.
dvander@171
   466
    TokenKind kind = FindIdentifier(literal());
dvander@171
   467
    if (kind != TOK_NONE) {
dvander@171
   468
        putChar(c);
dvander@171
   469
        return kind;
dvander@171
   470
    }
dvander@171
   471
dvander@172
   472
    if (c == ':' && allowTags_)
dvander@171
   473
        return TOK_LABEL;
dvander@171
   474
dvander@171
   475
    putChar(c);
dvander@171
   476
dvander@171
   477
    // _ is a special case which acts as a tag and a keyword.
dvander@171
   478
    if (!strcmp(literal(), "_"))
dvander@133
   479
        return TOK_UNDERSCORE;
dvander@171
   480
dvander@171
   481
    return TOK_NAME;
dvander@0
   482
}
dvander@0
   483
dvander@0
   484
TokenKind
dvander@0
   485
Scanner::next()
dvander@0
   486
{
dvander@0
   487
    assert(!pushed_);
dvander@0
   488
dvander@0
   489
    for (;;) {
dvander@25
   490
        begin_ = cur_;
dvander@25
   491
dvander@0
   492
        char c = getChar();
dvander@0
   493
        switch (c) {
dvander@0
   494
          case '/':
dvander@0
   495
          {
dvander@0
   496
            c = getChar();
dvander@0
   497
            if (c == '/') {
dvander@0
   498
                eatSingleLine();
dvander@0
   499
                break;
dvander@0
   500
            }
dvander@0
   501
            if (c == '*') {
dvander@25
   502
                if (!eatComment()) {
dvander@25
   503
                    cc_.reportError(begin(), Message_UnterminatedComment);
dvander@0
   504
                    return TOK_ERROR;
dvander@25
   505
                }
dvander@0
   506
                break;
dvander@0
   507
            }
dvander@0
   508
            putChar(c);
dvander@0
   509
            return TOK_SLASH;
dvander@0
   510
          }
dvander@0
   511
dvander@25
   512
          case '\n':
dvander@25
   513
          case '\r':
dvander@25
   514
            calcNewLine(c);
dvander@25
   515
            break;
dvander@25
   516
dvander@0
   517
          case ';': return TOK_SEMICOLON;
dvander@0
   518
          case '{': return TOK_LBRACE;
dvander@0
   519
          case '}': return TOK_RBRACE;
dvander@0
   520
          case '(': return TOK_LPAREN;
dvander@0
   521
          case ')': return TOK_RPAREN;
dvander@0
   522
          case '[': return TOK_LBRACKET;
dvander@0
   523
          case ']': return TOK_RBRACKET;
dvander@78
   524
          case '~': return TOK_TILDE;
dvander@83
   525
          case '?': return TOK_QMARK;
dvander@83
   526
          case ':': return TOK_COLON;
dvander@2
   527
dvander@68
   528
          case '.':
dvander@68
   529
            c = getChar();
dvander@68
   530
            if (c == '.') {
dvander@68
   531
                c = getChar();
dvander@68
   532
                if (c == '.')
dvander@68
   533
                    return TOK_ELLIPSES;
dvander@148
   534
                cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
dvander@148
   535
                return TOK_ERROR;
dvander@68
   536
            }
dvander@148
   537
            putChar(c);
dvander@148
   538
            return TOK_DOT;
dvander@68
   539
dvander@2
   540
          case '*':
dvander@2
   541
            c = getChar();
dvander@2
   542
            if (c == '=')
dvander@2
   543
                return TOK_ASSIGN_MUL;
dvander@2
   544
            putChar(c);
dvander@2
   545
            return TOK_STAR;
dvander@2
   546
dvander@2
   547
          case '+':
dvander@2
   548
            c = getChar();
dvander@2
   549
            if (c == '=')
dvander@2
   550
                return TOK_ASSIGN_ADD;
dvander@23
   551
            if (c == '+')
dvander@23
   552
                return TOK_INCREMENT;
dvander@2
   553
            putChar(c);
dvander@2
   554
            return TOK_PLUS;
dvander@2
   555
dvander@8
   556
          case '&':
dvander@22
   557
            c = getChar();
dvander@22
   558
            if (c == '=')
dvander@22
   559
                return TOK_ASSIGN_BITAND;
dvander@75
   560
            if (c == '&')
dvander@75
   561
                return TOK_AND;
dvander@22
   562
            putChar(c);
dvander@8
   563
            return TOK_BITAND;
dvander@8
   564
dvander@8
   565
          case '|':
dvander@22
   566
            c = getChar();
dvander@22
   567
            if (c == '=')
dvander@22
   568
                return TOK_ASSIGN_BITOR;
dvander@75
   569
            if (c == '|')
dvander@75
   570
                return TOK_OR;
dvander@22
   571
            putChar(c);
dvander@8
   572
            return TOK_BITOR;
dvander@8
   573
dvander@8
   574
          case '^':
dvander@22
   575
            c = getChar();
dvander@22
   576
            if (c == '=')
dvander@22
   577
                return TOK_ASSIGN_BITXOR;
dvander@22
   578
            putChar(c);
dvander@8
   579
            return TOK_BITXOR;
dvander@8
   580
dvander@82
   581
          case '%':
dvander@82
   582
            c = getChar();
dvander@82
   583
            if (c == '=')
dvander@82
   584
                return TOK_ASSIGN_MOD;
dvander@82
   585
            putChar(c);
dvander@82
   586
            return TOK_PERCENT;
dvander@82
   587
dvander@22
   588
          case '-':
dvander@22
   589
            c = getChar();
dvander@22
   590
            if (c == '=')
dvander@22
   591
                return TOK_ASSIGN_SUB;
dvander@23
   592
            if (c == '-')
dvander@23
   593
                return TOK_DECREMENT;
dvander@22
   594
            putChar(c);
dvander@22
   595
            return TOK_MINUS;
dvander@22
   596
dvander@0
   597
          case ',': return TOK_COMMA;
dvander@0
   598
          case '\0': return TOK_EOF;
dvander@0
   599
dvander@74
   600
          case '!':
dvander@74
   601
            c = getChar();
dvander@74
   602
            if (c == '=')
dvander@74
   603
                return TOK_NOTEQUALS;
dvander@74
   604
            putChar(c);
dvander@74
   605
            return TOK_NOT;
dvander@74
   606
dvander@0
   607
          case '=':
dvander@0
   608
            c = getChar();
dvander@0
   609
            if (c == '=')
dvander@0
   610
                return TOK_EQUALS;
dvander@0
   611
            putChar(c);
dvander@0
   612
            return TOK_ASSIGN;
dvander@0
   613
dvander@148
   614
dvander@0
   615
          case '<':
dvander@0
   616
            c = getChar();
dvander@0
   617
            if (c == '=')
dvander@0
   618
                return TOK_LE;
dvander@2
   619
            if (c == '<') {
dvander@2
   620
                c = getChar();
dvander@2
   621
                if (c == '=')
dvander@2
   622
                    return TOK_ASSIGN_SHL;
dvander@138
   623
                putChar(c);
dvander@2
   624
                return TOK_SHL;
dvander@2
   625
            }
dvander@0
   626
            putChar(c);
dvander@0
   627
            return TOK_LT;
dvander@0
   628
dvander@0
   629
          case '>':
dvander@0
   630
            c = getChar();
dvander@0
   631
            if (c == '=')
dvander@0
   632
                return TOK_GE;
dvander@8
   633
            if (c == '>') {
dvander@8
   634
                c = getChar();
dvander@22
   635
                if (c == '>') {
dvander@22
   636
                    c = getChar();
dvander@22
   637
                    if (c == '=')
dvander@22
   638
                        return TOK_ASSIGN_USHR;
dvander@22
   639
                    putChar(c);
dvander@8
   640
                    return TOK_USHR;
dvander@22
   641
                }
dvander@8
   642
                return TOK_SHR;
dvander@8
   643
            }
dvander@0
   644
            putChar(c);
dvander@0
   645
            return TOK_GT;
dvander@0
   646
dvander@0
   647
          case ' ':
dvander@0
   648
          case '\t':
dvander@0
   649
          case '\f':
dvander@0
   650
            break;
dvander@0
   651
dvander@21
   652
          case '"':
dvander@21
   653
            return stringLiteral();
dvander@21
   654
dvander@0
   655
          default:
dvander@0
   656
            if (c >= '0' && c <= '9')
dvander@4
   657
                return numberLiteral(c);
dvander@0
   658
            if (c == '_' || (isascii(c) && isalpha(c)))
dvander@0
   659
                return identifier(c);
dvander@25
   660
            cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
dvander@0
   661
            return TOK_ERROR;
dvander@0
   662
        }
dvander@0
   663
    }
dvander@0
   664
}
dvander@0
   665
dvander@0
   666
TokenKind
dvander@0
   667
Scanner::scan()
dvander@0
   668
{
dvander@0
   669
    if (pushed_) {
dvander@0
   670
        pushed_ = false;
dvander@0
   671
        return lastToken_;
dvander@0
   672
    }
dvander@0
   673
    lastToken_ = next();
dvander@0
   674
    return lastToken_;
dvander@0
   675
}
dvander@0
   676
dvander@0
   677
TokenKind
dvander@0
   678
Scanner::peek()
dvander@0
   679
{
dvander@0
   680
    if (pushed_)
dvander@0
   681
        return lastToken_;
dvander@0
   682
    scan();
dvander@0
   683
    pushed_ = true;
dvander@0
   684
    return lastToken_;
dvander@0
   685
}