我一直在为我的命令行项目制作一个简单的解释器,但是我最近偶然发现了一个我不知道原因的问题。
以下是代码:
// cls.h
#pragma once
#include <iostream>
#include <string>
#include <iomanip>
enum id {undef, kwd, idt, opr, val}; // Ignore idt
extern std::string keywords[]; // Declaring the keywords array
extern std::string operators[]; // Declaring the operators array
class Token
{
id ID;
std::string value;
public:
Token() {
ID = undef;
value = "";
}
void SetID(id ID) {
this->ID = ID;
}
void SetValue(std::string value) {
this->value = value;
}
id GetID() {
return ID;
}
std::string GetValue() {
return value;
}
};
std::string UserInput();
void Lexical(Token *token, int nstr, std::string str, int ntok);
// cls.cpp
#include <iostream>
// Definitions of the keywords and operators arrays
std::string keywords[] = {
"echo",
"exit"
};
std::string operators[] = {
"+",
"-",
"/",
"%"
};
// input.cpp
#include "cls.h"
std::string UserInput() // Function to take user's input
{
std::string input;
std::getline(std::cin, input);
return input;
}
// lex.cpp
#include "cls.h"
// To check whether a token is a keyword
static bool aKeyword(std::string str)
{
for (int i = 0; i < 10; i++) {
if (keywords[i] == str)
return true;
}
return false;
}
// To check whether a token is an operator
static bool aOperator(std::string str)
{
for (int i = 0; i < 10; i++) {
if (operators[i] == str)
return true;
}
return false;
}
void Lexical(Token *token, int ntok, std::string str, int nstr)
{
// Working the tokens' values
int idx = 0;
bool fspace = false;
std::string plh[256];
for (int i = 0; i < nstr; i++) {
if ((str.at(i) == ' ') && (fspace == false)) {
idx++;
fspace = true;
continue;
} else
if ((str.at(i) == ' ') && (fspace == true)) {
continue;
}
plh[idx].append(&(str.at(i)), 1);
fspace = false;
}
for (int i = 0; i < ntok; i++) {
(token + i)->SetValue(plh[i]);
}
// Working the tokens' IDs
// Checking whether a token is a keyword, an operator or a value
for (int i = 0; i < ntok; i++) {
if (aKeyword((token + i)->GetValue()) == true) {
(token + i)->SetID(kwd);
} else
if (aOperator((token + i)->GetValue()) == true) { // <--- The problem
(token + i)->SetID(opr);
} else {
(token + i)->SetID(val);
}
}
}
// init.cpp
#include "cls.h"
int main()
{
std::string usinput;
Token token[256];
std::cout << "User input: ";
usinput = UserInput(); // Taking user's input
Lexical(token, 256, usinput, (int) usinput.size()); // Calling the lexical function
// Outputting the tokens' values and IDs (The IDs is in the parentheses)
for (int i = 0; i < 10; i++) {
std::cout << "Token[" << i << "] = "
<< token[i].GetValue()
<< std::setfill(' ')
<< std::setw(15 - (token[i].GetValue()).size())
<< "(" << token[i].GetID() << ")"
<< std::endl;
}
return 0;
}
当 Lexical 函数尝试使用 ID 的关键字 (kwd)、运算符 (opr) 或值 (val) 对标记进行检查和分类时,就会出现问题。在以下枚举 id 的定义中
enum id {undef, kwd, idt, opr, val};
很明显,opr 应该具有值 3(对于运算符),但是当我尝试运行程序并看到输出时,它给出的值是 1(对于关键字)
benanthony@DESKTOP-QI9Q4LV:~/codes/CLine$ make
g++ init.cpp lex.cpp input.cpp cls.cpp -Wall -Wextra -o CLine
benanthony@DESKTOP-QI9Q4LV:~/codes/CLine$ ./CLine
User input: Hello there + - Rand - Lett - echo yes
Token[0] = Hello (4)
Token[1] = there (4)
Token[2] = + (1)
Token[3] = - (1)
Token[4] = Rand (4)
Token[5] = - (1)
Token[6] = Lett (4)
Token[7] = - (1)
Token[8] = echo (1)
Token[9] = yes (4)
token[2]、token[3]、token[5]和token[7]中的+和-的ID值应该是3。
我尝试过通过更改 ID 名称等方式来解决此问题,但仍然不起作用。
这似乎是一个简单的问题,但我仍然不知道如何解决。我是否遗漏了什么或犯了什么错误?
该问题是由
aKeyword
和 aOperator
方法中的未定义行为引起的。您正在比较数组之外的字符串,i < 10
,如果修复这些字符串,您将获得预期的结果:
// To check whether a token is a keyword
static bool aKeyword(std::string str)
{
for (int i = 0; i < 2; i++) {
if (keywords[i] == str)
return true;
}
return false;
}
// To check whether a token is an operator
static bool aOperator(std::string str)
{
for (int i = 0; i < 4; i++) {
if (operators[i] == str)
return true;
}
return false;
}