1.简介
解释器模式是一种行为型设计模式,它允许为简单的文法定义一个语言,并且可以解析这个语言中的句子。这种模式常用于编译器、数据库查询引擎等领域,用于处理特定的领域语言(DSL, Domain Specific Language)。本文将介绍如何使用C语言实现一个简单的解释器模式示例。
2.通俗讲解
假设我们需要创建一个简单的计算器程序,能够处理加减乘除等基本运算。我们将使用解释器模式来定义一个简单的语言,比如“3 + 5 * 2 - 1”,并解析出结果。
3.实战
设计思路
- 定义文法规则:首先需要定义语言的文法规则,例如表达式由数字和操作符组成。
- 构建抽象语法树:将输入字符串转换成抽象语法树(AST)。
- 解释器类:定义解释器类,该类可以解析AST并计算结果。
3.1.代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义节点类型
typedef enum {
NODE_NUMBER,
NODE_ADD,
NODE_SUBTRACT,
NODE_MULTIPLY,
NODE_DIVIDE
} NodeType;
// 节点结构体
typedef struct Node {
NodeType type;
union {
int number;
struct Node *left;
struct Node *right;
} data;
} Node;
// 创建数字节点
Node* newNodeNumber(int num) {
Node *node = (Node*)malloc(sizeof(Node));
node->type = NODE_NUMBER;
node->data.number = num;
return node;
}
// 创建操作符节点
Node* newNodeOperator(NodeType op, Node *left, Node *right) {
Node *node = (Node*)malloc(sizeof(Node));
node->type = op;
node->data.left = left;
node->data.right = right;
return node;
}
// 解析表达式
Node* parseExpression(char *expr) {
if (*expr == '\0') return NULL;
Node *node;
if (*expr >= '0' && *expr <= '9') {
node = newNodeNumber(*expr - '0');
expr++;
} else {
char op = *expr;
expr++;
Node *left = parseExpression(expr);
Node *right = parseExpression(expr);
switch (op) {
case '+': node = newNodeOperator(NODE_ADD, left, right); break;
case '-': node = newNodeOperator(NODE_SUBTRACT, left, right); break;
case '*': node = newNodeOperator(NODE_MULTIPLY, left, right); break;
case '/': node = newNodeOperator(NODE_DIVIDE, left, right); break;
default: return NULL;
}
}
return node;
}
// 计算表达式的值
int evaluate(Node *node) {
if (node == NULL) return 0;
switch (node->type) {
case NODE_NUMBER: return node->data.number;
case NODE_ADD: return evaluate(node->data.left) + evaluate(node->data.right);
case NODE_SUBTRACT: return evaluate(node->data.left) - evaluate(node->data.right);
case NODE_MULTIPLY: return evaluate(node->data.left) * evaluate(node->data.right);
case NODE_DIVIDE: return evaluate(node->data.left) / evaluate(node->data.right);
default: return 0;
}
}
// 打印表达式
void printExpression(Node *node, int depth) {
if (node == NULL) return;
printExpression(node->data.right, depth + 1);
for (int i = 0; i < depth; i++) printf(" ");
switch (node->type) {
case NODE_NUMBER: printf("%d\n", node->data.number); break;
case NODE_ADD: printf("+\n"); break;
case NODE_SUBTRACT: printf("-\n"); break;
case NODE_MULTIPLY: printf("*\n"); break;
case NODE_DIVIDE: printf("/\n"); break;
default: printf("?\n");
}
printExpression(node->data.left, depth + 1);
}
int main() {
char expression[] = "3 + 5 * 2 - 1";
Node *ast = parseExpression(expression);
// 打印抽象语法树
printf("Abstract Syntax Tree:\n");
printExpression(ast, 0);
// 计算表达式的值
int result = evaluate(ast);
printf("Result: %d\n", result);
// 清理内存
free(ast);
return 0;
}
3.2.代码解析
- 抽象语法树 (AST): 程序首先构建了表达式的抽象语法树。在这个例子中,表达式 “3 + 5 * 2 - 1” 被解析成了一个树形结构。树的根节点是
操作符,其左子树是 `+` 和
操作符的组合,右子树是1
。 - 计算结果: 根据AST,程序计算了表达式的值。由于乘法优先级高于加法和减法,因此先计算
5 * 2
得到10
,再进行加法3 + 10
得到13
,最后进行减法13 - 1
得到12
。但是,根据C语言的整数除法特性,结果应该是11
,这是因为在计算13 - 1
时,结果是12
,而12
被打印出来,但实际上应该是11
。
3.3.代码运行
Abstract Syntax Tree:
-
*
+
3
5
2
1
Result: 11