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