我开始编写一个lexer,并创建了下面的文件来测试到目前为止一切是否正常:
Main.cpp
#include <iostream>
#include "Lexer.h"
#include "Token.h"
int main(void)
{
std::string str(""); // I'll use this to test expressions
Lexer lexer(str);
std::vector<Token> tokens = lexer.lex();
for(auto it = tokens.begin(); it != tokens.end(); ++it)
{
std::string str;
switch(it->type)
{
case TokenType::_EOF:
str = "EOF";
break;
case TokenType::ERROR:
str = "ERROR";
break;
case TokenType::SEMICOLON:
str = "SEMICOLON";
break;
case TokenType::PLUS:
str = "PLUS";
break;
case TokenType::LESS_THAN:
str = "LESS_THAN";
break;
case TokenType::GREATER_THAN:
str = "GREATER_THAN";
break;
case TokenType::INT:
str = "INT";
break;
case TokenType::ID:
str = "ID";
break;
case TokenType::WHITESPACE:
str = "WHITESPACE";
break;
default:
str = "<Unknown Token>";
}
std::cout << str << ", detail='" << it->detail << "'" << std::endl;
}
return 0;
}lexer.lex()行抛出一个异常。在Lexer.h里看
std::vector<Token> Lexer::lex(void)
{
// Reset input pointer
inputPtr = 0;
updateCurrentChar();
// Read tokens until EOF
std::vector<Token> tokens;
Token *token = nullptr;
do
{
token = getNext();
tokens.push_back(*token);
} while(token->type != TokenType::_EOF);
return tokens;
}tokens.push_back(*token)行正在抛出一个异常:

我试着查看了push_back() 这里的信息,发现:
如果发生重新分配,则使用容器的分配器分配存储,这可能会在失败时抛出异常(对于默认的分配器,如果分配请求不成功,则引发bad_alloc )。
这似乎是我的问题,但我不明白为什么分配请求不会成功。
为了完整起见,以下是所有文件:
Token.h
#pragma once
#include <string>
enum class TokenType
{
_EOF,
ERROR,
EQUALS,
SEMICOLON,
PLUS,
LESS_THAN,
GREATER_THAN,
INT,
ID,
WHITESPACE
};
struct Token
{
TokenType type;
std::string detail;
};low.h
#pragma once
#include <string>
#include <vector>
#include "Token.h"
class Lexer
{
public:
Lexer(std::string);
~Lexer(void);
std::vector<Token> lex(void);
private:
Token* getNext(void);
void updateCurrentChar(void);
void increment(void);
bool matchCurrent(char);
bool isWhitespace(char) const;
bool isDigit(char) const;
bool isLetter(char) const;
bool isLowercaseLetter(char) const;
bool isUppercaseLetter(char) const;
std::string readWhitespace(void);
std::string readInt(void);
std::string readId(void);
std::string input;
int inputPtr;
char currentChar;
const char EOF_CHAR;
};Lexer.cpp
#include "Lexer.h"
Lexer::Lexer(std::string _input)
: input(_input), EOF_CHAR(-1)
{
}
Lexer::~Lexer(void)
{
}
std::vector<Token> Lexer::lex(void)
{
// Reset input pointer
inputPtr = 0;
updateCurrentChar();
// Read tokens until EOF
std::vector<Token> tokens;
Token *token = nullptr;
do
{
token = getNext();
tokens.push_back(*token);
} while(token->type != TokenType::_EOF);
return tokens;
}
void Lexer::updateCurrentChar(void)
{
currentChar = inputPtr < input.length()
? input[inputPtr]
: EOF_CHAR;
}
void Lexer::increment(void)
{
inputPtr++;
updateCurrentChar();
}
bool Lexer::matchCurrent(char toMatch)
{
if(toMatch == currentChar)
{
increment();
return true;
}
return false;
}
Token* Lexer::getNext(void)
{
Token token;
if(isWhitespace(currentChar))
{
token.type = TokenType::WHITESPACE;
token.detail = readWhitespace();
return &token;
}
if(isDigit(currentChar))
{
token.type = TokenType::INT;
token.detail = readInt();
return &token;
}
if(isLetter(currentChar))
{
token.type = TokenType::ID;
token.detail = readId();
return &token;
}
if(currentChar == EOF_CHAR)
{
token.type = TokenType::_EOF;
return &token;
}
switch(currentChar)
{
case ';':
token.type = TokenType::SEMICOLON;
case '=':
token.type = TokenType::EQUALS;
case '<':
token.type = TokenType::LESS_THAN;
case '>':
token.type = TokenType::GREATER_THAN;
case '+':
token.type = TokenType::PLUS;
default:
token.type = TokenType::ERROR;
token.detail = currentChar;
}
increment();
return &token;
}
std::string Lexer::readWhitespace(void)
{
std::string ws;
while(isWhitespace(currentChar))
{
ws += currentChar;
increment();
}
return ws;
}
std::string Lexer::readInt(void)
{
std::string ws;
while(isDigit(currentChar))
{
ws += currentChar;
increment();
}
return ws;
}
std::string Lexer::readId(void)
{
std::string ws;
while(isWhitespace(currentChar))
{
ws += currentChar;
increment();
}
return ws;
}
bool Lexer::isDigit(char c) const
{
return c >= '0' && c <= '9';
}
bool Lexer::isLetter(char c) const
{
return isLowercaseLetter(c)
|| isUppercaseLetter(c);
}
bool Lexer::isLowercaseLetter(char c) const
{
return c >= 'a' && c <= 'z';
}
bool Lexer::isUppercaseLetter(char c) const
{
return c >= 'A' && c <= 'Z';
}
bool Lexer::isWhitespace(char c) const
{
switch(c)
{
case ' ':
case '\n':
case '\t':
case '\r':
return true;
default:
return false;
}
}发布于 2013-08-10 12:22:13
问题是,在getNext中,返回指向局部变量的指针。请记住,当函数返回时,所有局部变量都将被解构,因此指针现在指向已解构的对象。或者,由于局部变量在堆栈上,并且堆栈在函数调用之间被重用,所以它现在可以指向完全不同的东西。您取消引用这个现在无效的指针的结果会导致未定义的行为,而未定义的行为通常会导致崩溃,但它也可能看起来很有效,但数据却完全搞砸了。
当然,最明显的解决方案是返回对象的副本,即不要使用指针(这通常是一个很好的提示)。
https://stackoverflow.com/questions/18161787
复制相似问题