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