jitcraft/Scanner.cpp
changeset 0 c455ebb9a5dc
child 2 46fc53b8fd2f
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/jitcraft/Scanner.cpp	Mon Jun 25 02:57:28 2012 -0700
     1.3 @@ -0,0 +1,227 @@
     1.4 +/*
     1.5 + * Copyright (C) 2012 David Anderson
     1.6 + *
     1.7 + * This file is part of JITCraft.
     1.8 + *
     1.9 + * JITCraft is free software: you can redistribute it and/or modify it under
    1.10 + * the terms of the GNU General Public License as published by the Free
    1.11 + * Software Foundation, either version 3 of the License, or (at your option)
    1.12 + * any later version.
    1.13 + * 
    1.14 + * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
    1.15 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License along with
    1.19 + * JITCraft. If not, see http://www.gnu.org/licenses/.
    1.20 + */
    1.21 +#include <assert.h>
    1.22 +#include <ctype.h>
    1.23 +#include "Scanner.h"
    1.24 +
    1.25 +using namespace jc;
    1.26 +
    1.27 +const char *jc::TokenNames[] =
    1.28 +{
    1.29 +#define _(name, str) str,
    1.30 +    TOKENMAP(_)
    1.31 +#undef _
    1.32 +    NULL
    1.33 +};
    1.34 +
    1.35 +Scanner::Scanner(const char *stream, size_t length)
    1.36 +  : stream_(stream),
    1.37 +    length_(length),
    1.38 +    pushed_(false),
    1.39 +    saved_('\0'),
    1.40 +    pos_(stream_)
    1.41 +{
    1.42 +}
    1.43 +
    1.44 +char
    1.45 +Scanner::getChar()
    1.46 +{
    1.47 +    if (saved_ != '\0') {
    1.48 +        char temp = saved_;
    1.49 +        saved_ = '\0';
    1.50 +        return temp;
    1.51 +    }
    1.52 +    if (pos_ >= stream_ + length_)
    1.53 +        return '\0';
    1.54 +    return *pos_++;
    1.55 +}
    1.56 +
    1.57 +void
    1.58 +Scanner::putChar(char c)
    1.59 +{
    1.60 +    assert(saved_ == '\0');
    1.61 +    saved_ = c;
    1.62 +}
    1.63 +
    1.64 +void
    1.65 +Scanner::eatSingleLine()
    1.66 +{
    1.67 +    char c;
    1.68 +    while ((c = getChar()) != '\0') {
    1.69 +        if (c == '\n' || c == '\r')
    1.70 +            break;
    1.71 +    }
    1.72 +}
    1.73 +
    1.74 +bool
    1.75 +Scanner::eatComment()
    1.76 +{
    1.77 +    char c;
    1.78 +
    1.79 +    while ((c = getChar()) != '\0') {
    1.80 +        while (c == '*') {
    1.81 +            c = getChar();
    1.82 +            if (c == '\0')
    1.83 +                return false;
    1.84 +            if (c == '/')
    1.85 +                return true;
    1.86 +        }
    1.87 +    }
    1.88 +
    1.89 +    return false;
    1.90 +}
    1.91 +
    1.92 +TokenKind
    1.93 +Scanner::integerLiteral(char first)
    1.94 +{
    1.95 +    literal_ = first;
    1.96 +
    1.97 +    for (;;) {
    1.98 +        char c = getChar();
    1.99 +        if (c < '0' || c > '9') {
   1.100 +            putChar(c);
   1.101 +            break;
   1.102 +        }
   1.103 +        literal_ += c;
   1.104 +    }
   1.105 +
   1.106 +    return TOK_INTEGER_LITERAL;
   1.107 +}
   1.108 +
   1.109 +TokenKind
   1.110 +Scanner::identifier(char first)
   1.111 +{
   1.112 +    literal_ = first;
   1.113 +
   1.114 +    for (;;) {
   1.115 +        char c = getChar();
   1.116 +        if (!isascii(c) || (!isalnum(c) && c != '_')) {
   1.117 +            putChar(c);
   1.118 +            break;
   1.119 +        }
   1.120 +        literal_ += c;
   1.121 +    }
   1.122 +
   1.123 +    if (literal_ == "new")
   1.124 +        return TOK_NEW;
   1.125 +    if (literal_ == "for")
   1.126 +        return TOK_FOR;
   1.127 +    if (literal_ == "return")
   1.128 +        return TOK_RETURN;
   1.129 +    if (literal_ == "if")
   1.130 +        return TOK_IF;
   1.131 +    if (literal_ == "else")
   1.132 +        return TOK_ELSE;
   1.133 +    return TOK_NAME;
   1.134 +}
   1.135 +
   1.136 +TokenKind
   1.137 +Scanner::next()
   1.138 +{
   1.139 +    assert(!pushed_);
   1.140 +
   1.141 +    for (;;) {
   1.142 +        char c = getChar();
   1.143 +        switch (c) {
   1.144 +          case '/':
   1.145 +          {
   1.146 +            c = getChar();
   1.147 +            if (c == '/') {
   1.148 +                eatSingleLine();
   1.149 +                break;
   1.150 +            }
   1.151 +            if (c == '*') {
   1.152 +                if (!eatComment())
   1.153 +                    return TOK_ERROR;
   1.154 +                break;
   1.155 +            }
   1.156 +            putChar(c);
   1.157 +            return TOK_SLASH;
   1.158 +          }
   1.159 +
   1.160 +          case ';': return TOK_SEMICOLON;
   1.161 +          case '{': return TOK_LBRACE;
   1.162 +          case '}': return TOK_RBRACE;
   1.163 +          case '(': return TOK_LPAREN;
   1.164 +          case ')': return TOK_RPAREN;
   1.165 +          case '[': return TOK_LBRACKET;
   1.166 +          case ']': return TOK_RBRACKET;
   1.167 +          case '*': return TOK_STAR;
   1.168 +          case '+': return TOK_PLUS;
   1.169 +          case '-': return TOK_MINUS;
   1.170 +          case ',': return TOK_COMMA;
   1.171 +          case '\0': return TOK_EOF;
   1.172 +
   1.173 +          case '=':
   1.174 +            c = getChar();
   1.175 +            if (c == '=')
   1.176 +                return TOK_EQUALS;
   1.177 +            putChar(c);
   1.178 +            return TOK_ASSIGN;
   1.179 +
   1.180 +          case '<':
   1.181 +            c = getChar();
   1.182 +            if (c == '=')
   1.183 +                return TOK_LE;
   1.184 +            putChar(c);
   1.185 +            return TOK_LT;
   1.186 +
   1.187 +          case '>':
   1.188 +            c = getChar();
   1.189 +            if (c == '=')
   1.190 +                return TOK_GE;
   1.191 +            putChar(c);
   1.192 +            return TOK_GT;
   1.193 +
   1.194 +          case ' ':
   1.195 +          case '\t':
   1.196 +          case '\r':
   1.197 +          case '\f':
   1.198 +          case '\n':
   1.199 +            break;
   1.200 +
   1.201 +          default:
   1.202 +            if (c >= '0' && c <= '9')
   1.203 +                return integerLiteral(c);
   1.204 +            if (c == '_' || (isascii(c) && isalpha(c)))
   1.205 +                return identifier(c);
   1.206 +            return TOK_ERROR;
   1.207 +        }
   1.208 +    }
   1.209 +}
   1.210 +
   1.211 +TokenKind
   1.212 +Scanner::scan()
   1.213 +{
   1.214 +    if (pushed_) {
   1.215 +        pushed_ = false;
   1.216 +        return lastToken_;
   1.217 +    }
   1.218 +    lastToken_ = next();
   1.219 +    return lastToken_;
   1.220 +}
   1.221 +
   1.222 +TokenKind
   1.223 +Scanner::peek()
   1.224 +{
   1.225 +    if (pushed_)
   1.226 +        return lastToken_;
   1.227 +    scan();
   1.228 +    pushed_ = true;
   1.229 +    return lastToken_;
   1.230 +}