大话设计模式C语言之解释器模式

解释器模式

解释器模式(Interpreter Pattern)解释器模式是一种行为型设计模式,它定义了一种语言文法的表示,并且定义了一个解释器,用于解释该语言中的句子。

案例代码

下面例子实现检测 (temp > 60 AND pressure < 50) OR motor_on == 0 表达式。

抽象表达式(Abstract Expression)

定义解释器的接口interpret(context)方法,供子类实现具体解析逻辑,所有的表达式都必须实现该接口。

expr.h
1
2
3
4
5
6
7
8
9
10
11
12
#ifndef EXPR_H
#define EXPR_H

typedef struct Expression Expression;
typedef struct Context Context;

int expr_evaluate(Expression *expr, Context *ctx);

void expr_destroy(Expression *expr);

#endif

expr_internal.h
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef EXPR_INTERNAL_H
#define EXPR_INTERNAL_H

#include "expr.h"

struct Expression
{
int (*evaluate)(Expression *, Context *);
void (*destroy)(Expression *);
};

#endif

expr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "expr_internal.h"

int expr_evaluate(Expression *expr, Context *ctx)
{
if (!expr || !expr->evaluate)
return 0;

return expr->evaluate(expr, ctx);
}

void expr_destroy(Expression *expr)
{
if (!expr || !expr->destroy)
return;

expr->destroy(expr);
}

终结符表达式(Terminal Expression)

处理最基本的解析单元,如数字、变量、常量等,可以被解释。

Constant Expression
constant_expr.h
1
2
3
4
5
6
7
8
9
#ifndef CONSTANT_EXPR_H
#define CONSTANT_EXPR_H

#include "expr.h"

Expression *constant_expr_create(int value);

#endif

constant_expr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "expr_internal.h"
#include <stdlib.h>

typedef struct
{
Expression base;
int value;

} ConstantExpr;

static int evaluate(Expression *expr, Context *ctx)
{
(void)ctx;
return ((ConstantExpr *)expr)->value;
}

static void destroy(Expression *expr)
{
free(expr);
}

Expression *constant_expr_create(int value)
{
ConstantExpr *e = calloc(1, sizeof(ConstantExpr));

if (!e)
return NULL;

e->base.evaluate = evaluate;
e->base.destroy = destroy;

e->value = value;

return (Expression *)e;
}

Variable Expression
variable_expr.h
1
2
3
4
5
6
7
8
9
#ifndef VARIABLE_EXPR_H
#define VARIABLE_EXPR_H

#include "expr.h"

Expression *variable_expr_create(const char *name);

#endif

variable_expr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include "expr_internal.h"
#include "context.h"
#include <stdlib.h>
#include <string.h>

#define NAME_LEN 32

typedef struct
{
Expression base;
char name[NAME_LEN];

} VariableExpr;

static int evaluate(Expression *expr, Context *ctx)
{
VariableExpr *self = (VariableExpr *)expr;

int value = 0;

context_get(ctx, self->name, &value);

return value;
}

static void destroy(Expression *expr)
{
free(expr);
}

Expression *variable_expr_create(const char *name)
{
VariableExpr *e = calloc(1, sizeof(VariableExpr));

if (!e)
return NULL;

e->base.evaluate = evaluate;
e->base.destroy = destroy;

strncpy(e->name, name, NAME_LEN - 1);

return (Expression *)e;
}

非终结符表达式(NonTerminal Expression)

表示语言中的复合元素,处理复杂表达式,如加法、乘法、布尔运算等,通常包含多个 Expression 组成的子表达式。

Compare Expression
compare_expr.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef COMPARE_EXPR_H
#define COMPARE_EXPR_H

#include "expr.h"

typedef enum
{
CMP_GT,
CMP_LT,
CMP_EQ

} CompareOp;

Expression *compare_expr_create(
Expression *left,
Expression *right,
CompareOp op);

#endif

compare_expr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdlib.h>
#include "compare_expr.h"
#include "expr_internal.h"

typedef struct
{
Expression base;
Expression *left;
Expression *right;
CompareOp op;

} CompareExpr;

static int evaluate(Expression *expr, Context *ctx)
{
CompareExpr *self = (CompareExpr *)expr;

int l = expr_evaluate(self->left, ctx);
int r = expr_evaluate(self->right, ctx);

switch (self->op)
{
case CMP_GT: return l > r;
case CMP_LT: return l < r;
case CMP_EQ: return l == r;
}

return 0;
}

static void destroy(Expression *expr)
{
CompareExpr *self = (CompareExpr *)expr;

expr_destroy(self->left);
expr_destroy(self->right);

free(self);
}

Expression *compare_expr_create(
Expression *left,
Expression *right,
CompareOp op)
{
CompareExpr *e = calloc(1, sizeof(CompareExpr));

if (!e)
return NULL;

e->base.evaluate = evaluate;
e->base.destroy = destroy;

e->left = left;
e->right = right;
e->op = op;

return (Expression *)e;
}

Logical Expression
logical_expr.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef LOGICAL_EXPR_H
#define LOGICAL_EXPR_H

#include "expr.h"

typedef enum
{
LOGIC_AND,
LOGIC_OR

} LogicOp;

Expression *logical_expr_create(
Expression *left,
Expression *right,
LogicOp op);

#endif

logical_expr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <stdlib.h>
#include "logical_expr.h"
#include "expr_internal.h"

typedef struct
{
Expression base;
Expression *left;
Expression *right;
LogicOp op;

} LogicalExpr;

static int evaluate(Expression *expr, Context *ctx)
{
LogicalExpr *self = (LogicalExpr *)expr;

int l = expr_evaluate(self->left, ctx);
int r = expr_evaluate(self->right, ctx);

if (self->op == LOGIC_AND)
return l && r;

return l || r;
}

static void destroy(Expression *expr)
{
LogicalExpr *self = (LogicalExpr *)expr;

expr_destroy(self->left);
expr_destroy(self->right);

free(self);
}

Expression *logical_expr_create(
Expression *left,
Expression *right,
LogicOp op)
{
LogicalExpr *e = calloc(1, sizeof(LogicalExpr));

if (!e)
return NULL;

e->base.evaluate = evaluate;
e->base.destroy = destroy;

e->left = left;
e->right = right;
e->op = op;

return (Expression *)e;
}

上下文(Context)

包含解释器的全局信息,存储和维护表达式的全局信息,如变量值、运行环境等。对解释器的调用和解释器之间的信息交换都通过上下文进行。

context.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef CONTEXT_H
#define CONTEXT_H

typedef struct Context Context;

Context *context_create(void);

void context_set(Context *, const char *name, int value);

int context_get(Context *, const char *name, int *value);

void context_destroy(Context *);

#endif

context_internal.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef CONTEXT_INTERNAL_H
#define CONTEXT_INTERNAL_H

#include "context.h"

#define MAX_VARIABLES 16
#define MAX_NAME_LEN 32

typedef struct
{
char name[MAX_NAME_LEN];
int value;
int used;

} Variable;

struct Context
{
Variable vars[MAX_VARIABLES];
};

#endif

context.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include "context_internal.h"
#include <stdlib.h>
#include <string.h>

Context *context_create(void)
{
return calloc(1, sizeof(Context));
}

void context_set(Context *ctx, const char *name, int value)
{
if (!ctx || !name)
return;

for (int i = 0; i < MAX_VARIABLES; i++)
{
if (ctx->vars[i].used &&
strcmp(ctx->vars[i].name, name) == 0)
{
ctx->vars[i].value = value;
return;
}
}

for (int i = 0; i < MAX_VARIABLES; i++)
{
if (!ctx->vars[i].used)
{
strncpy(ctx->vars[i].name, name, MAX_NAME_LEN - 1);
ctx->vars[i].used = 1;
ctx->vars[i].value = value;
return;
}
}
}

int context_get(Context *ctx, const char *name, int *value)
{
if (!ctx || !name || !value)
return -1;

for (int i = 0; i < MAX_VARIABLES; i++)
{
if (ctx->vars[i].used &&
strcmp(ctx->vars[i].name, name) == 0)
{
*value = ctx->vars[i].value;
return 0;
}
}

return -1;
}

void context_destroy(Context *ctx)
{
free(ctx);
}

测试客户端代码 main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include "context.h"
#include "constant_expr.h"
#include "variable_expr.h"
#include "compare_expr.h"
#include "logical_expr.h"

int main(void)
{
Context *ctx = context_create();

context_set(ctx, "temp", 75);
context_set(ctx, "pressure", 30);
context_set(ctx, "motor_on", 1);

//(temp > 60 AND pressure < 50) OR motor_on == 0
Expression *expr = logical_expr_create(logical_expr_create(compare_expr_create(variable_expr_create("temp"), constant_expr_create(60), CMP_GT), compare_expr_create(variable_expr_create("pressure"), constant_expr_create(50), CMP_LT), LOGIC_AND), compare_expr_create(variable_expr_create("motor_on"), constant_expr_create(0), CMP_EQ), LOGIC_OR);

int result = expr_evaluate(expr, ctx);

printf("Rule Result = %s\n", result ? "TRUE" : "FALSE");

expr_destroy(expr);
context_destroy(ctx);

while (1);
return 0;
}

总结

   解释器模式适用于需要将一种语言或规则转化为另一种语言或规则的场景,比如SQL解析器、数学公式解析器、编程语言解释器、机器翻译、正则表达式引擎、模板解析器、配置文件解析器等。但在实际应用中,需要注意解释器模式可能会影响程序的性能,以及语法规则的复杂度可能会降低代码的可读性和可维护性。

解释器模式的优点如下:

  • 易于扩展新的语法规则,只需添加新的解释器即可。
  • 可以对语言进行灵活的控制和调试,增加了代码的可读性和可维护性。
  • 可以避免使用大量的条件判断语句,使代码更加简洁和易于理解。

解释器模式的缺点如下:

  • 大规模使用解释器模式可能会影响程序的性能,因为表达式需要被递归地解释。
  • 在解释器模式中,我们需要考虑语法规则,并将其抽象为表达式,这可能会增加代码的复杂度,降低代码的可读性和可维护性。
  • 解释器模式的性能通常不如编译器性能高,因为解释器需要通过运行时解释语言,而编译器可以在编译阶段优化代码。
  • 如果语法规则过于复杂,可能需要大量的解释器来解释,导致代码量过大,可读性降低。
  • 可能会出现环路依赖的问题,导致解释器无法进行解释。