题解 P3695 【CYaRon!语】
BLOG中查看体验更佳。
前言
给出解释器的相关内容,国外文献及国内翻译,文献所用语言是Python,并且国内只有计算器的部分(加减乘除,相反数)。
所以我写代码的时候更加注重工程风格,在保证无BUG前提下尽量严格,并且不依赖于其他库(STL)。
如果在代码中调用了我没有讲的函数,那么请看最后的完整代码,因为函数实在太多了。类中必要的public函数基本都已省略。代码中...表示省略
解释器概述
建议先编写一个表达式求值,不过这道题需要处理的中缀表达式中只有加减运算,所以比较简单。
写一下的解释器通用的逻辑。
TOKEN
翻译为令牌、标记,我理解为单词,包括单关键字、变量名、符号等。
主要是将一段字符串转换为计算机可以理解的东西,通常是数字。每个TOKEN都有它自己的类型,并且存储原有的内容。TOKEN通常是解释器的最小单元。
具体实现可以用define、const、enum之一,我使用了enum。这些都是程序员自己定义的。例如此题(部分):
enum TOKEN_TYPE {
INTEGER = 1, // 整形(数字)
OPERATOR_PLUS, // 操作符 '+'
...,
T_COLON, // 符号 ':'
T_COMMA // 符号 ','
};
// TOKEN 类型
存储时即使用类或者结构体,代码(部分):
class TOKEN {
private:
TOKEN_TYPE _typ; // TOKEN类型
const char *_val; // 原有的值
unsigned int _len; // 值长度
// 注:使用 const char* 是为了方便
...
};
LEXER
翻译为词法分析器。简单来说,输入一堆字符(本题是整个程序),经过LEXER的处理,输出一系列的TOKEN(按顺序)。
对于大部分OIER来说,都写过暴力模拟的表达式求值。两者想似,但是LEXER分析一段字符串后输出TOKEN并不直接让LEXER来处理。所以它还有个别名为scanner。
存储时依然是使用类或者结构体,代码(部分):
class LEXER {
private:
const char *_text; // 一堆字符(本题是整个程序)
unsigned int _len; // 字符长度
unsigned int _pos; // 处理到第_pos个字符(从 0 开始)
char _ch; // 当前字符为_ch
...
}
然后要在类中写几个函数,分别是扫描下一个字符、跳过间隔符、跳过数字等。扫描下一个字符时要判断是否已到字符串结尾,代码:
void nextChar() {
this->_ch = (this->_pos >= this->_len ? 0 : this->_text[++this->_pos]);
return;
}
unsigned int skipNumber() {
unsigned int res = 0;
while(this->_ch != 0 && isNumber(this->_ch)) ++res, nextChar();
// isNumber(x) 表示 x 是否为数字
return res;
}
LEXER最重要的作用还是获取TOKEN,对于本题的代码(部分):
TOKEN getNextToken() {
while(this->_ch != 0) {
if(isSpacer(this->_ch)) {
// isSpacer(x) 表示 x 是否为间隔符
skipSpace();
// skipSpace() 跳过间隔符
continue;
}
if(isNumber(this->_ch)) {
// isNumber(x) 表示 x 是否为数字
const char *pos = getPosString();
return TOKEN(INTEGER, pos, skipNumber());
}
if(this->_ch == '+') {
nextChar();
return TOKEN(OPERATOR_PLUS);
}
...
if(this->_ch == ',') {
nextChar();
return TOKEN(T_COMMA);
}
if(this->_ch == ':') {
nextChar();
return TOKEN(T_COLON);
}
return TOKEN(T_NULL);
// 无法处理
}
return TOKEN(T_EOF);
// 结尾
}
NODE
NODE是我起的名字,因为它代表语法树的一个节点。获得程序根节点的返回值意味着运行整个程序。
每个NODE存储一个TOKEN,TOKEN的类型表示NODE的任务类型,TOKEN的值表示NODE可用的参数。NODE还有它的子节点,每个NODE运作时都会用指定方式使它的子节点运作。
它的类在此题如下:
class NODE {
private:
TOKEN _token; // 必需的
NODE **_list; // 子节点指针数组
bool _multi;
unsigned int _siz, _msiz;
bool _flag;
}
_multi、_msiz、_flag是我的实现,可能有更好的方法。至于它们的作用会在下面再讲。
NODE的两个核心方法为getValue和setValue,但对于本题来说,前置更复杂一些。
PARSER
翻译为语法分析器。输入TOKEN,生成语法树,输出根节点。因为此题不涉及运算符先后顺序,所以只需实现判断。循环等语法即可。
PARSER类的代码(部分):
class PARSER {
private:
LEXER _lexer; // 绑定的LEXER
TOKEN _tok; // 当前处理的TOKEN
...
};
同样在类中有获得下一个TOKEN的函数,代码:
void nextToken(TOKEN_TYPE typ) {
if(this->_tok.getType() == typ) this->_tok = this->_lexer.getNextToken();
return;
}
有方法parser用来生成语法树,内部由多个函数递归实现,因语言而异。
CALCULATOR
推荐先写一个加减乘除相反数的计算器来练手,此处为我的代码。
本题分析
计算器和本题差别还是很大的,对比发现,本题多了变量、判断、循环、数组、输出、比较,少了乘除。再进一步发现,少了运算优先级的问题。
TOKEN
我定义本题有30个TOKEN,可以说是非常多了,所以请对照完整代码。然后只讲一些本题的核心语法和逻辑。
如果不知道某个TOKEN_TYPE的含义,那么请看在代码里的LEXER中TOKEN是如何产生的。
VARIABLE
至于为什么先讲这个,因为程序一上来就要定义变量。我是针对本题只有int来解决的,解释器文献的这部分在C++中出入较大。
本着不用STL的原则,因此无法使用map。我并不想也不会写红黑树,而本题只有10个变量,所以就链表查询变量了。代码(部分):
class VAR {
private:
const char *_name; // 变量名
unsigned int _len; // 变量名长度
VAR *_nxt; // 链表下一个
int *_mem; // 内存
int _s, _t; // 数组下标起始和终止,非数组中分别为0、1
...
};
然后定义一个链表首节点var_first,写两个函数分别为getVar、setVar,前置是根据名称获得VAR指针,后者实际上是注册一个VAR。
BLOCK
BLOCK是一个TOKEN类型,目的表示代码块。一个{}所包含的内容即是一个代码块,特别的,整个程序也是一个代码块。
根据语言的特性,代码块的第一行通常为控制语句,比如判断、循环、vars等。如果没有控制语句,设置BLOCK为默认控制语句,代表只运行一次,vars也是如此。
我们将根据第0个子节点的返回值是否为true循环运行BLOCK中的内容。
NODE
所以问题又来了,如何存储子节点列表。我们并不想使用vector,只好自己实现。
根据vector的思想,只需要在列表已满时将空间扩大一倍(变为两倍),效率比较高。
为了方便使用,特化出自运算、一元运算和二元运算,以提高代码复杂度便于编写。
按照规则,BLOCK表示代码块时是多元运算。如果BLOCK表示控制语句时是自运算。
因此在代码中用_multi表示是否为多元运算,_siz记录子节点数,_msiz记录分配内存大小。
VARIABLE_DEFINE
首先知道格式为name:type/array[type, s..t],即名称:类型/数组[类型, 起始下标..终止下标]。
那么组成它的TOKEN包括VARIABLE_NAME、VARIABLE_TYPE、BRACKET_LEFT、BRACKET_RIGHT、INTEGER、T_DOT。
语法树构建时,我把T_COLON设为多元运算符,VARIABLE_NAME设为第0子节点,省去了VARIABLE_TYPE,如果为数组再新建两个INTEGER节点当做T_COLON的子节点。
此为parserVar函数。
运作时判断子节点数,VAR中的_s为第1个子节点的值,_t为第2个子节点的值,无子节点视为0、1。
EXPRESSION
表达式已经是老生常谈的问题了,所以不再细说。
遇到表达式调用parserSecond,内部调用parserThird,分析出常量、变量、加减运算符,遇到括号(然而此题没有,才发现)就递归调用parserSecond。
VARIABLE
读取变量的值时先读入VARIABLE_NAME,再判断是否有BRACKET_LEFT(左中括号),之后再调用parserSecond读取内部表达式,再读入BRACKET_RIGHT,然而本题内部表达式并不会很复杂。
所以此处我把VARIABLE_NAME设为一元运算符,仅有的一个子节点为下标(不是数组则为0)。
YOSORO | ASSIGN(SET)
先分析输出和赋值语句,因为它们逻辑最简单且作用相反(似乎并不相反)。
当PARSER遇到类型为T_COLON的TOKEN时,那么就视为要执行函数了,进入parserCall函数。
YOSORO为一元运算符,仅有一个子节点为表达式。ASSIGN为二元运算符,左儿子为变量名,右儿子为表达式。
IF(IHU) | WHILE
之所以它们放在一块,是因为语法相同。当遇到对应的TOKEN时,依次读取比较操作符、逗号、表达式、逗号、表达式,函数为parserIhu和parserWhile。
IF和WHILE为一元运算符,仅有一个子节点为比较操作符的返回值。众所周知比较操作符是二元运算符,这个非常简单。
为了判断一个节点是否第一次运作,所以在NODE中加入了变量_flag。
IF和WHILE的差别在于IF后需要将_flag设为true。
BLOCK 1
在BLOCK运作结束后还需要重置子节点的状态信息(如_flag),以让下次进入BLOCK节点时所有的子节点是新的。
FOR(HOR)
FOR应该是比较麻烦的一个,我将它设为多元运算符。
函数为parserHor,依次读取表达式、逗号、表达式、逗号、表达式。三个表达式依次为它的三个子节点。
运作时先判断_flag,第一次需要给第0个子节点赋值为第1个子节点的值。然后再通过判断第0个子节点是否小于等于第2个子节点。
还需要让FOR节点也要有一个赋值的方法,为了在循环结束时给第0个子节点加1。
BLOCK 2
所以BLOCK结束时还要调用控制语句(第0个子节点)的赋值操作,当然值就不必设置了。
GLOBAL FUNCTION
运行程序使用calc,参数为整个程序和字符串长度。
int calc(const char *exp, unsigned int len) {
char *_exp = new char[len]();
for(unsigned int i = 0; i < len; i++) _exp[i] = exp[i];
// 改为用户不可变内存,安全起见
int res = PARSER(LEXER(_exp, len)).parser()->getValue();
delete[] _exp;
return res;
}
并未使用strcmp,手写了equalString用来判断字符串是否相等。
剩下的方法都比较简单,自行理解即可。
图例
如果还不懂可以看图例,纯手工良心制作。
代码
无O2用时37ms内存820KB
#include <stdio.h>
namespace CALCULATOR {
enum TOKEN_TYPE {
INTEGER = 1,
OPERATOR_PLUS,
OPERATOR_MINUS,
OPERATOR_LT,
OPERATOR_GT,
OPERATOR_LE,
OPERATOR_GE,
OPERATOR_EQ,
OPERATOR_NEQ,
PAR_LEFT,
PAR_RIGHT,
BRACKET_LEFT,
BRACKET_RIGHT,
BLOCK_LEFT,
BLOCK_RIGHT,
PROGRAM,
BLOCK,
VARIABLE_NAME,
VARIABLE_TYPE,
VARS,
YOSORO,
OPERATOR_ASSIGN,
IHU,
HOR,
WHILE,
T_DOT,
T_EOF,
T_NULL,
T_COLON,
T_COMMA
};
bool equalString(const char *a, const char *b, unsigned int len) {
for(unsigned int i = 0; i < len; i++)
if(a[i] != b[i]) return 0;
return 1;
}
class VAR {
private:
const char *_name;
unsigned int _len;
VAR *_nxt;
int *_mem;
int _s, _t;
public:
VAR() : _name(), _len(), _nxt(), _mem(), _t(), _s() {}
VAR(const char *name, unsigned int len) : _name(name), _len(len), _nxt(), _mem(), _t(), _s() {}
VAR(const char *name, unsigned int len, int s, int t) : _name(name), _len(len), _nxt(), _mem(), _t(t), _s(s) {
this->_mem = new int[this->_t - this->_s]();
}
unsigned int getLen() const {
return this->_len;
}
void setValue(int x, int v) {
this->_mem[x - this->_s] = v;
return;
}
const char *getName() const {
return this->_name;
}
VAR *getNext() const {
return this->_nxt;
}
void setNext(VAR *v) {
this->_nxt = v;
}
int getValue(int x) {
return this->_mem[x - this->_s];
}
} var_first;
VAR *getVar(const char *name, unsigned int len) {
VAR *p = &var_first;
while(p) {
if(p->getLen() == len && equalString(p->getName(), name, len)) return p;
p = p->getNext();
}
return 0;
}
void setVar(VAR *nxt) {
VAR *p = &var_first;
while(p->getNext()) p = p->getNext();
p->setNext(nxt);
return;
}
class TOKEN {
private:
TOKEN_TYPE _typ;
const char *_val;
unsigned int _len;
public:
TOKEN(TOKEN_TYPE typ = T_NULL) : _typ(typ), _val(), _len() {}
TOKEN(TOKEN_TYPE type, const char *val, unsigned int len) : _val(val), _typ(type), _len(len) {}
TOKEN_TYPE getType() const {
return this->_typ;
}
const char *getValue() const {
return this->_val;
}
unsigned int getLength() const {
return this->_len;
}
~TOKEN() {}
};
int toInteger(const char *val, unsigned int len) {
int res = 0;
for(unsigned int i = 0; i < len; i++) res = res * 10 + val[i] - '0';
return res;
}
unsigned int toString(int val, char *res) {
unsigned int len = 0;
int val2 = val;
while(val2) ++len, val2 /= 10;
unsigned int len2 = len;
while(val) res[--len2] = '0' + val % 10, val /= 10;
if(len == 0) res[len = 1] = '0';
return len;
}
bool isNumber(char ch) {
return ch >= '0' && ch <= '9';
}
bool isLetter(char ch) {
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}
bool isSpacer(char ch) {
return ch == ' ' || ch == '\n' || ch == '\t';
}
class LEXER {
private:
const char *_text;
unsigned int _len;
unsigned int _pos;
char _ch;
void nextChar() {
this->_ch = (this->_pos >= this->_len ? 0 : this->_text[++this->_pos]);
return;
}
void skipSpace() {
while(this->_ch != 0 && isSpacer(this->_ch)) nextChar();
return;
}
unsigned int skipNumber() {
unsigned int res = 0;
while(this->_ch != 0 && isNumber(this->_ch)) ++res, nextChar();
return res;
}
unsigned int skipWord() {
unsigned int res = 0;
while(this->_ch != 0 && isLetter(this->_ch)) ++res, nextChar();
return res;
}
const char *getPosString() const {
return _text + _pos;
}
public:
LEXER(const char *text, unsigned int len) : _text(text), _len(len), _pos() {
this->_ch = (this->_pos >= this->_len ? 0 : this->_text[this->_pos]);
}
~LEXER() {}
TOKEN getNextToken() {
while(this->_ch != 0) {
if(isSpacer(this->_ch)) {
skipSpace();
continue;
}
if(isNumber(this->_ch)) {
const char *pos = getPosString();
return TOKEN(INTEGER, pos, skipNumber());
}
if(isLetter(this->_ch)) {
const char *pos = getPosString();
unsigned int len = skipWord();
if(len == 2 && equalString("lt", pos, len)) return TOKEN(OPERATOR_LT);
if(len == 2 && equalString("gt", pos, len)) return TOKEN(OPERATOR_GT);
if(len == 2 && equalString("le", pos, len)) return TOKEN(OPERATOR_LE);
if(len == 2 && equalString("ge", pos, len)) return TOKEN(OPERATOR_GE);
if(len == 2 && equalString("eq", pos, len)) return TOKEN(OPERATOR_EQ);
if(len == 3 && equalString("neq", pos, len)) return TOKEN(OPERATOR_NEQ);
if(len == 3 && equalString("set", pos, len)) return TOKEN(OPERATOR_ASSIGN);
if(len == 3 && equalString("ihu", pos, len)) return TOKEN(IHU);
if(len == 3 && equalString("hor", pos, len)) return TOKEN(HOR);
if(len == 3 && equalString("int", pos, len)) return TOKEN(VARIABLE_TYPE, pos, len);
if(len == 4 && equalString("vars", pos, len)) return TOKEN(VARS);
if(len == 5 && equalString("while", pos, len)) return TOKEN(WHILE);
if(len == 5 && equalString("array", pos, len)) return TOKEN(VARIABLE_TYPE, pos, len);
if(len == 6 && equalString("yosoro", pos, len)) return TOKEN(YOSORO);
return TOKEN(VARIABLE_NAME, pos, len);
}
if(this->_ch == '+') {
nextChar();
return TOKEN(OPERATOR_PLUS);
}
if(this->_ch == '-') {
nextChar();
return TOKEN(OPERATOR_MINUS);
}
if(this->_ch == '(') {
nextChar();
return TOKEN(PAR_LEFT);
}
if(this->_ch == ')') {
nextChar();
return TOKEN(PAR_RIGHT);
}
if(this->_ch == '.') {
nextChar();
nextChar();
return TOKEN(T_DOT);
}
if(this->_ch == ',') {
nextChar();
return TOKEN(T_COMMA);
}
if(this->_ch == ':') {
nextChar();
return TOKEN(T_COLON);
}
if(this->_ch == '[') {
nextChar();
return TOKEN(BRACKET_LEFT);
}
if(this->_ch == ']') {
nextChar();
return TOKEN(BRACKET_RIGHT);
}
if(this->_ch == '{') {
nextChar();
return TOKEN(BLOCK_LEFT);
}
if(this->_ch == '}') {
nextChar();
return TOKEN(BLOCK_RIGHT);
}
return TOKEN(T_NULL);
}
return TOKEN(T_EOF);
}
};
class NODE {
private:
TOKEN _token;
NODE **_list;
bool _multi;
unsigned int _siz, _msiz;
bool _flag;
int getConstantValue() {
if(this->_token.getType() == INTEGER) return toInteger(this->_token.getValue(), this->_token.getLength());
if(this->_token.getType() == VARS && this->_flag == 0) return this->_flag = 1;
if(this->_token.getType() == BLOCK && this->_flag == 0) return this->_flag = 1;
return 0;
}
int getUnaryValue() {
if(this->_token.getType() == OPERATOR_PLUS) return +this->_list[0]->getValue();
if(this->_token.getType() == OPERATOR_MINUS) return -this->_list[0]->getValue();
if(this->_token.getType() == YOSORO) return printf("%d ", this->_list[0]->getValue()), 0;
if(this->_token.getType() == VARIABLE_NAME) return getVar(this->_token.getValue(), this->_token.getLength())->getValue(this->_list[0]->getValue());
if(this->_token.getType() == IHU && this->_flag == 0) return this->_flag = 1, this->_list[0]->getValue();
if(this->_token.getType() == WHILE) return this->_list[0]->getValue();
return 0;
}
int getBinValue() {
if(this->_token.getType() == OPERATOR_PLUS) return this->_list[0]->getValue() + this->_list[1]->getValue();
if(this->_token.getType() == OPERATOR_MINUS) return this->_list[0]->getValue() - this->_list[1]->getValue();
if(this->_token.getType() == OPERATOR_LT) return this->_list[0]->getValue() < this->_list[1]->getValue();
if(this->_token.getType() == OPERATOR_GT) return this->_list[0]->getValue() > this->_list[1]->getValue();
if(this->_token.getType() == OPERATOR_LE) return this->_list[0]->getValue() <= this->_list[1]->getValue();
if(this->_token.getType() == OPERATOR_GE) return this->_list[0]->getValue() >= this->_list[1]->getValue();
if(this->_token.getType() == OPERATOR_EQ) return this->_list[0]->getValue() == this->_list[1]->getValue();
if(this->_token.getType() == OPERATOR_NEQ) return this->_list[0]->getValue() != this->_list[1]->getValue();
if(this->_token.getType() == OPERATOR_ASSIGN) return this->_list[0]->setValue(this->_list[1]->getValue());
return 0;
}
int getMultiValue() {
if(this->_token.getType() == T_COLON) {
if(this->_siz == 1) {
this->_list[0]->registerVar(0, 1);
}
else {
this->_list[0]->registerVar(this->_list[1]->getValue(), this->_list[2]->getValue());
}
return 0;
}
if(this->_token.getType() == BLOCK) {
while(this->_list[0]->getValue()) {
for(unsigned int i = 1; i < this->_siz; i++) {
this->_list[i]->getValue();
}
this->_list[0]->setValue(0);
}
this->clearST();
}
if(this->_token.getType() == HOR) {
if(this->_flag == 0) {
this->_list[0]->setValue(this->_list[1]->getValue());
this->_flag = 1;
}
return this->_list[0]->getValue() <= this->_list[2]->getValue();
}
return 0;
}
int registerVar(int s, int t) {
VAR *p = new VAR(this->_token.getValue(), this->_token.getLength(), s, t);
setVar(p);
return 0;
}
int setValue(int v) {
if(this->_token.getType() == VARIABLE_NAME) {
VAR *p = getVar(this->_token.getValue(), this->_token.getLength());
p->setValue(this->_list[0]->getValue(), v);
}
if(this->_token.getType() == HOR) {
this->_list[0]->setValue(this->_list[0]->getValue() + 1);
}
return 0;
}
void clearST() {
if(this->_siz == -1) return;
for(unsigned int i = 0; i < this->_siz; i++) this->_list[i]->_flag = 0, this->_list[i]->clearST();
}
public:
NODE(bool multi = 0) : _token(T_NULL), _list(), _siz(-1), _multi(multi), _msiz(), _flag() {
if(this->_multi) this->_siz = 0;
}
NODE(TOKEN token) : _token(token), _list(), _siz(), _multi(), _msiz(), _flag() {}
NODE(TOKEN token, NODE *expr0) : _token(token), _siz(1), _multi(), _msiz(1), _flag() {
this->_list = new NODE *[this->_siz]();
this->_list[0] = expr0;
}
NODE(TOKEN token, NODE *expr0, NODE *expr1) : _token(token), _siz(2), _multi(), _msiz(2), _flag() {
this->_list = new NODE *[this->_siz]();
this->_list[0] = expr0;
this->_list[1] = expr1;
}
~NODE() {
if(this->_list)
for(unsigned int i = 0; i < this->_siz; i++) delete this->_list[i];
}
int getValue() {
if(this->_multi) return getMultiValue();
switch(_siz) {
case 0: return getConstantValue();
case 1: return getUnaryValue();
case 2: return getBinValue();
default: break;
}
return 0;
}
void setToken(const TOKEN &token) {
this->_token = token;
return;
}
void push(NODE *expr0) {
if(this->_siz >= this->_msiz) {
unsigned int lmsiz = this->_msiz;
this->_msiz = (this->_siz + 1) * 2;
NODE **list = new NODE *[this->_msiz]();
for(unsigned int i = 0; i < this->_siz; i++) list[i] = this->_list[i];
if(this->_list) {
delete[] this->_list;
}
this->_list = list;
}
this->_list[this->_siz++] = expr0;
return;
}
int getSize() const {
return this->_siz;
}
};
class PARSER {
private:
LEXER _lexer;
TOKEN _tok;
void nextToken(TOKEN_TYPE typ) {
if(this->_tok.getType() == typ) this->_tok = this->_lexer.getNextToken();
return;
}
NODE *parserThird() {
TOKEN token = this->_tok;
if(token.getType() == INTEGER) {
nextToken(INTEGER);
return new NODE(token);
}
if(token.getType() == PAR_LEFT) {
nextToken(PAR_LEFT);
NODE *res = parserSecond();
nextToken(PAR_RIGHT);
return res;
}
if(token.getType() == VARIABLE_NAME) {
nextToken(VARIABLE_NAME);
NODE *res;
if(this->_tok.getType() == BRACKET_LEFT) {
nextToken(BRACKET_LEFT);
res = parserSecond();
nextToken(BRACKET_RIGHT);
}
else {
res = new NODE();
}
return new NODE(token, res);
}
if(token.getType() == OPERATOR_PLUS || token.getType() == OPERATOR_MINUS) {
nextToken(token.getType());
return new NODE(token, parserThird());
}
return new NODE();
}
NODE *parserSecond() {
NODE *res = parserThird();
while(this->_tok.getType() != T_EOF) {
TOKEN token = this->_tok;
if(token.getType() == OPERATOR_PLUS || token.getType() == OPERATOR_MINUS) {
nextToken(token.getType());
res = new NODE(token, res, parserThird());
}
else {
break;
}
}
return res;
}
NODE *parserCall() {
TOKEN token = this->_tok;
if(token.getType() == YOSORO) {
nextToken(YOSORO);
return new NODE(token, parserSecond());
}
if(token.getType() == OPERATOR_ASSIGN) {
nextToken(OPERATOR_ASSIGN);
NODE *res = parserThird();
nextToken(T_COMMA);
return new NODE(token, res, parserSecond());
}
return new NODE();
}
NODE *parserVar() {
NODE *res = new NODE(1);
res->push(new NODE(this->_tok));
nextToken(VARIABLE_NAME);
res->setToken(this->_tok);
nextToken(T_COLON);
if(this->_tok.getLength() == 5) {
nextToken(VARIABLE_TYPE);
nextToken(BRACKET_LEFT);
nextToken(VARIABLE_TYPE);
nextToken(T_COMMA);
res->push(new NODE(this->_tok));
nextToken(INTEGER);
nextToken(T_DOT);
nextToken(T_DOT);
res->push(new NODE(this->_tok));
nextToken(INTEGER);
nextToken(BRACKET_RIGHT);
}
else {
nextToken(VARIABLE_TYPE);
}
return res;
}
NODE *parserIhu() {
NODE *res;
nextToken(IHU);
TOKEN token = this->_tok;
if(token.getType() == OPERATOR_LT || token.getType() == OPERATOR_GT || token.getType() == OPERATOR_LE || this->_tok.getType() == OPERATOR_GE || this->_tok.getType() == OPERATOR_EQ || token.getType() == OPERATOR_NEQ) {
nextToken(token.getType());
nextToken(T_COMMA);
NODE *res1 = parserSecond();
nextToken(T_COMMA);
NODE *res2 = parserSecond();
res = new NODE(token, res1, res2);
}
else {
res = new NODE();
}
return new NODE(TOKEN(IHU), res);
}
NODE *parserHor() {
NODE *res = new NODE(1);
res->setToken(this->_tok);
nextToken(HOR);
res->push(parserSecond());
nextToken(T_COMMA);
res->push(parserSecond());
nextToken(T_COMMA);
res->push(parserSecond());
return res;
}
NODE *parserWhile() {
NODE *res;
nextToken(WHILE);
TOKEN token = this->_tok;
if(token.getType() == OPERATOR_LT || token.getType() == OPERATOR_GT || token.getType() == OPERATOR_LE || this->_tok.getType() == OPERATOR_GE || this->_tok.getType() == OPERATOR_EQ || token.getType() == OPERATOR_NEQ) {
nextToken(token.getType());
nextToken(T_COMMA);
NODE *res1 = parserSecond();
nextToken(T_COMMA);
NODE *res2 = parserSecond();
res = new NODE(token, res1, res2);
}
else {
res = new NODE();
}
return new NODE(TOKEN(WHILE), res);
}
NODE *parserFirst() {
NODE *res = new NODE(1);
res->setToken(TOKEN(BLOCK));
while(this->_tok.getType() != T_EOF) {
TOKEN token = this->_tok;
if(token.getType() == VARS) {
nextToken(VARS);
res->push(new NODE(TOKEN(VARS)));
}
else if(token.getType() == IHU) {
res->push(parserIhu());
}
else if(token.getType() == HOR) {
res->push(parserHor());
}
else if(token.getType() == WHILE) {
res->push(parserWhile());
}
else if(token.getType() == VARIABLE_NAME) {
if(res->getSize() == 0) res->push(new NODE(TOKEN(BLOCK)));
res->push(parserVar());
}
else if(token.getType() == T_COLON) {
if(res->getSize() == 0) res->push(new NODE(TOKEN(BLOCK)));
nextToken(T_COLON);
res->push(parserCall());
}
else if(token.getType() == BLOCK_LEFT) {
if(res->getSize() == 0) res->push(new NODE(TOKEN(BLOCK)));
nextToken(BLOCK_LEFT);
res->push(parserFirst());
nextToken(BLOCK_RIGHT);
}
else {
break;
}
}
return res;
}
public:
PARSER(LEXER lexer) : _lexer(lexer) {
this->_tok = this->_lexer.getNextToken();
}
NODE *parser() {
return parserFirst();
}
~PARSER() {}
};
int calc(const char *exp, unsigned int len) {
char *_exp = new char[len]();
for(unsigned int i = 0; i < len; i++) _exp[i] = exp[i];
int res = PARSER(LEXER(_exp, len)).parser()->getValue();
delete[] _exp;
return res;
}
} // namespace CALCULATOR
#include <stdio.h>
#include <iostream>
using namespace std;
string str, str2;
int main() {
while(getline(cin, str2)) {
str += str2;
}
CALCULATOR::calc(str.c_str(), str.size());
return 0;
}
后记
题解写了半个下午,继续学习变量类型去了。