在上一篇中,我们实现了一个简单的加法解释器,它仅支持一位数加法,接下来,我们向解释器添加以下特性:
- 支持多位整数
- 可以跳过空格
- 支持减法
处理多位整数
上一篇中,我们直接使用单个字符来判断其所属的Token类型,为了支持多位整数,我们需要对连续字符串进行判断,所以我们需要在Interpreter类中实现一个advance函数:
void Interpreter::advance()
{
currentPos++;
if (currentPos >= strlen(text.c_str()))
{
currentChar = '\0';
}
else
{
currentChar = text.c_str()[currentPos];
}
}
然后,在getNextTokenPtr时,如果读取到第一个字符是整数,那么连续读取一直到当前字符不是整数为止,为此,实现一个integer函数:
int Interpreter::integer()
{
int result = 0;
while (isDigit(currentChar))
{
result *= 10;
result += currentChar - '0';
advance();
}
return result;
}
注意这里的isDigit,C++库有提供自带的isdigit函数,不过我还是自己实现了一个,因为将来我们不仅仅是需要isdigit这样子简单的判断,早晚都是要自己写的:
bool Interpreter::isDigit(char c)
{
return c >= '0' && c <= '9';
}
处理空格
处理空格比较简单,实现一个isSpace的判断函数,然后实现一个skipWhiteSpaces,遇到则跳过就行,同样的,我们不用C++库自带的issapce:
bool Interpreter::isSpace(char c)
{
return c == ' ' || c == '\t';
}
void Interpreter::skipWhiteSpaces()
{
while (isSpace(currentChar))
{
advance();
}
}
处理减法
处理减法则是跟处理加法的逻辑相同,只要往TokenType里加一个枚举值,然后在getNextToken时加一个判断就行,最终实现如下:
TokenPtr Interpreter::getNextTokenPtr()
{
while (currentChar != '\0')
{
if (isSpace(currentChar))
{
skipWhiteSpaces();
continue;
}
if (isDigit(currentChar))
{
return make_shared<Token>(TokenType::TT_INTEGER, integer());
}
if (currentChar == '+')
{
advance();
return make_shared<Token>(TokenType::TT_PLUS, '+');
}
if (currentChar == '-')
{
advance();
return make_shared<Token>(TokenType::TT_MINUS, '-');
}
raiseError();
}
return make_shared<Token>(TokenType::TT_EOF, NULL);
}
int Interpreter::expr()
{
currentTokenPtr = getNextTokenPtr();
TokenPtr left = currentTokenPtr;
eat(TokenType::TT_INTEGER);
TokenPtr op = currentTokenPtr;
if (op->getType() == TokenType::TT_PLUS ||
op->getType() == TokenType::TT_MINUS)
{
eat(op->getType());
}
else
{
raiseError();
}
TokenPtr right = currentTokenPtr;
eat(TokenType::TT_INTEGER);
switch (op->getType())
{
case TokenType::TT_MINUS:
return get<int>(left->getValue()) - get<int>(right->getValue());
case TokenType::TT_PLUS:
return get<int>(left->getValue()) + get<int>(right->getValue());
default:
raiseError();
}
return 0;
}
然后我们写一个main来验证:
#include<iostream>
#include<sstream>
#include "Interpreter.h"
#include "InterpreterException.h"
using namespace std;
int main()
{
try
{
while (true)
{
std::string text;
getline(cin, text);
Interpreter i(text);
cout << i.expr() << endl;
}
}
catch (InterpreterException e)
{
return 0;
}
}
注意这里用sstream的getline,如果直接cin,无法输入空格,现在,我们可以愉快地使用这个加减法解释器了,看起来已经有点样子了。