加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
Scanner.h 4.92 KB
一键复制 编辑 原始数据 按行查看 历史
li 提交于 2024-12-03 23:51 . Scanner
#pragma once
#include <string>
#include <vector>
#include "Token.h"
#include "Error.h"
using namespace std;
class Scanner {
string source;
vector<Token> tokens;
int start = 0;
int current = 0;
int line = 1;
public:
Scanner(string source) : source(source) {}
vector<Token> scanTokens() {
while (!isAtEnd()) {
start = current;
scanToken();
}
tokens.push_back(Token(TokenType::EOF_TOKEN, "", {}, line));
return tokens;
}
private:
void scanToken() {
char c = advance();
switch (c) {
// 关键字
case '(': addToken(TokenType::LEFT_PAREN); break;
case ')': addToken(TokenType::RIGHT_PAREN); break;
case '{': addToken(TokenType::LEFT_BRACE); break;
case '}': addToken(TokenType::RIGHT_BRACE); break;
case '[': addToken(TokenType::LEFT_BRACKET); break;
case ']': addToken(TokenType::RIGHT_BRACKET); break;
case ',': addToken(TokenType::COMMA); break;
case '.': addToken(TokenType::DOT); break;
case '-': addToken(TokenType::MINUS); break;
case '+': addToken(TokenType::PLUS); break;
case ';': addToken(TokenType::SEMICOLON); break;
case '*': addToken(TokenType::STAR); break;
// 二元运算符
case '!':
addToken(match('=')? TokenType::BANG_EQUAL : TokenType::BANG);
break;
case '=':
addToken(match('=')? TokenType::EQUAL_EQUAL : TokenType::EQUAL);
break;
case '<':
addToken(match('=')? TokenType::LESS_EQUAL : TokenType::LESS);
break;
case '>':
addToken(match('=')? TokenType::GREATER_EQUAL : TokenType::GREATER);
break;
// 注释
case '/':
if (match('/')) {
while (peek() != '\n' && !isAtEnd()) advance();
} else {
addToken(TokenType::SLASH);
}
break;
// 空白符
case ' ':
case '\r':
case '\t':
break;
case '\n':
line++;
break;
// 字符串
case '"': scanString(); break;
default:
// 数字
if (isDigit(c)) {
number();
// 标识符
} else if (isAlpha(c)) {
identifier();
// 错误
} else {
ostringstream oss;
oss << "Unexpected character: " << c;
errorLog(line, "", oss.str());
}
break;
}
}
bool isAlpha(char c) {
return (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
c == '_';
}
bool isAlphaNumeric(char c) {
return isAlpha(c) || isDigit(c);
}
void identifier() {
while (isAlphaNumeric(peek())) advance();
string text = source.substr(start, current - start);
TokenType type = keywords.count(text) > 0? keywords[text] : TokenType::IDENTIFIER;
addToken(type);
}
void number() {
while (isDigit(peek())) advance();
if (peek() == '.' && isDigit(peekNext())) {
advance();
while (isDigit(peek())) advance();
}
addToken(TokenType::NUMBER, source.substr(start, current - start));
}
char peekNext() {
if (current + 1 >= source.length()) return '\0';
return source[current + 1];
}
bool isDigit(char c) {
return c >= '0' && c <= '9';
}
bool isAtEnd() {
return current >= source.length();
}
char advance() {
return source[current++];
}
void addToken(TokenType type) {
string text = source.substr(start, current - start);
tokens.push_back(Token(type, text, Value{text}, line));
}
void addToken(TokenType type, string lexeme) {
if (type == TokenType::NUMBER)
return tokens.push_back(Token(type, lexeme, Value{stod(lexeme)}, line));
tokens.push_back(Token(type, lexeme, Value{lexeme}, line));
}
bool match(char expected) {
if (isAtEnd()) return false;
if (source[current] != expected) return false;
current++;
return true;
}
char peek() {
if (isAtEnd()) return '\0';
return source[current];
}
void scanString() {
while (peek() != '"' && !isAtEnd()) {
if (peek() == '\n') line++;
advance();
}
if (isAtEnd()) {
errorLog(line, "", "Unterminated string.");
return;
}
advance();
string value = source.substr(start + 1, current - start - 2);
addToken(TokenType::STRING, value);
return;
}
};
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化