C语言之用链表的方式解析和运算嵌套的波兰表达式
嵌套的波兰表达式,形如:(+ 1 (+ 2 (+ 3 (+ 4 5 )))) ,用数组模拟栈,来实现这个功能。
将上一篇文章的代码拿过来,进一步改进!
- C语言之用链表的方式解析与运算简单的波兰表达式
定义一个新的数据类型,嵌套的子表达式subexpr
#define DT_SUBEXPR 0X03
在表达式结构中的共用体中加入一个新的类型ExprNode *bval
- 让 DT_SUBEXPR 对应 ExprNode *bval
...
union {
char oval; //operator
long ival; //integer
ExprNode *bval; //subexpr
} V;
...
定义创建新的子表达式节点的函数,代码如下:
/* create a new sub express node */
ExprNode *
expr_node_new_sub (ExprNode *val)
{
ExprNode *node = (ExprNode*) malloc (sizeof(ExprNode));
node->expr.dt = DT_SUBEXPR;
node->expr.V.bval = val;
node->next = NULL;
return node;
}
释放链表时同时也要释放这种类型的节点,expr_node_free代码改造如下:
/* free the express node list */
void
expr_node_free (ExprNode *node)
{
while (node != NULL)
{
ExprNode *tmp = node->next;
if (node->expr.dt == DT_SUBEXPR)
expr_node_free (node->expr.V.bval);
free (node);
node = tmp;
}
}
out函数前定义一个用于缩进显示的表达式级别变量exprlv,out函数代码如下:
/* define output express info level */
static int exprlv = 0;
/* output express info */
void
out_expr_info (Expr expr)
{
for (int i = 0; i < exprlv; i++) printf (" ");
switch (expr.dt)
{
case DT_OPERATOR: printf (" OP: %c\n", expr.V.oval); break;
case DT_INTEGER : printf ("INT: %ld\n", expr.V.ival); break;
case DT_SUBEXPR : printf ("SUB:\n");
exprlv++; out_expinfo (expr.V.bval); exprlv--; break;
}
}
out函数代码如下:
/* output express value */
void
out_expr_value (Expr expr)
{
switch (expr.dt)
{
case DT_OPERATOR: printf (" %c", expr.V.oval); break;
case DT_INTEGER : printf (" %ld", expr.V.ival); break;
case DT_SUBEXPR : out_express (expr.V.bval); break;
}
}
在原来的parse_expr_string函数基础上,重新写一个parse_expr_string函数
- STSIZE,指定栈的深度,也就是表达式嵌套的深度!!!
/* define number length */
#define NBSIZE 32
/* define stack height */
#define STSIZE 32
/* parse express string to express node */
ExprNode *
parse_expr_string (char *estr)
{
ExprNode *root = NULL;
ExprNode *st[STSIZE] = {0};
char nbuf[NBSIZE] = {0};
int idx = 0, ndx = 1, lv = 0;
char c;
nbuf[0] = '+'; //default +
c = estr[idx];
while (c != 0)
{
switch (c)
{
case '0'...'9': //number
{
char n = estr[idx+1];
nbuf[ndx] = c; ndx++;
if (n == ' ' || n == ')')
{
long lt = strtol (nbuf, NULL, 10);
ExprNode *tmp = expr_node_new_int (lt);
st[lv-1] = expr_node_append (st[lv-1], tmp);
memset (nbuf, 0, NBSIZE); nbuf[0] = '+'; ndx = 1;
}
}
break;
case '+': case '-': case '*': case '/': //operator
{
if (c == '+' || c == '-')
{
char n = estr[idx+1];
if (n >= '0' && n <= '9')
{
nbuf[0] = c; break;
}
}
ExprNode *tmp = expr_node_new_op (c);
st[lv-1] = expr_node_append (st[lv-1], tmp);
}
break;
case '(':
{
lv++; //todo
if (lv > STSIZE) printf ("Error: Syntax error, Stack overflow!\n");
}
break;
case ')':
{
lv--;
if (lv == 0)
{
root = st[lv];
return root; //todo
}
else if (lv > 0)
{
ExprNode *sub = expr_node_new_sub (st[lv]);
st[lv-1] = expr_node_append (st[lv-1], sub);
st[lv] = NULL;
}
else
{ printf ("Error: Syntax error! Stack overflow!\n"); } //todo
}
break;
case ' ': //space
break;
defualt:
printf ("Syntax error!\n");
}
idx++; c = estr[idx];
}
return root;
}
交互输入表达式、运算、输出结果函数eval_express,代码如下:
/* interactive evalute express */
void
eval_express (void)
{
ExprNode *elist = NULL;
char buf[1024] = {0};
int idx = 0;
char c;
printf ("REPL:> ");
c = fgetc (stdin);
while (c != EOF)
{
if (c == '\n')
{
elist = parse_expr_string (buf);
printf ("-------------------------\n");
out_expinfo (elist);
printf ("-------------------------\n");
printf ("full expr:");
out_express (elist);
printf ("\n-------------------------\n");
printf ("Result : %ld\n", expr_node_compute (elist));
memset (buf, 0, 1024);
expr_node_free (elist); elist = NULL;
printf ("REPL:> ");
idx = 0; c = fgetc (stdin);
}
else
{
buf[idx] = c;
idx++; c = fgetc (stdin);
}
}
}
/**/
int
main (int argc, char *argv[])
{
eval_express ();
return 0;
}
//-----(+ 1 (+ 2 3))-----//
编译运行,结果如预期,输出如下:
songvm@ubuntu:~/works/notes/lisp$ gcc xb.c -o xb
songvm@ubuntu:~/works/notes/lisp$ ./xb
REPL:> (+ 9 (+ 8 (+ 7 (+ 6 (+ 5 (+ 4 (+ 3 (+ 2 (+ 1 0)))))))))
-------------------------
OP: +
INT: 9
SUB:
OP: +
INT: 8
SUB:
OP: +
INT: 7
SUB:
OP: +
INT: 6
SUB:
OP: +
INT: 5
SUB:
OP: +
INT: 4
SUB:
OP: +
INT: 3
SUB:
OP: +
INT: 2
SUB:
OP: +
INT: 1
INT: 0
-------------------------
full expr: ( + 9 ( + 8 ( + 7 ( + 6 ( + 5 ( + 4 ( + 3 ( + 2 ( + 1 0 ) ) ) ) ) ) ) ) )
-------------------------
Result : 45
REPL:> (+ (* 8 9) (/ 200 4))
-------------------------
OP: +
SUB:
OP: *
INT: 8
INT: 9
SUB:
OP: /
INT: 200
INT: 4
-------------------------
full expr: ( + ( * 8 9 ) ( / 200 4 ) )
-------------------------
Result : 122
REPL:>
完整代码如下:
/* filename: xb.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* compile : gcc xb.c -o xb */
/* run : ./xb */
/* define express datatype */
#define DT_OPERATOR 0X01
#define DT_INTEGER 0X02
#define DT_SUBEXPR 0X03
/* define express node struct */
typedef struct _ExpressNode ExprNode;
/* define express struct */
typedef struct _Express Expr;
struct _Express {
char name[7]; //todo save variable name
char dt; //express datatype
union {
char oval; //operator
long ival; //integer
ExprNode *bval; //subexpr
} V;
};
/* define express node struct */
//typedef struct _ExpressNode ExprNode;
struct _ExpressNode {
Expr expr;
ExprNode *next;
};
/* define function pointer for express node */
typedef void (*EPFunc) (Expr expr);
/* create a new operator express node */
ExprNode *
expr_node_new_op (char val)
{
ExprNode *node = (ExprNode*) malloc (sizeof(ExprNode));
node->expr.dt = DT_OPERATOR;
node->expr.V.oval = val;
node->next = NULL;
return node;
}
/* create a new integer express node */
ExprNode *
expr_node_new_int (long val)
{
ExprNode *node = (ExprNode*) malloc (sizeof(ExprNode));
node->expr.dt = DT_INTEGER;
node->expr.V.ival = val;
node->next = NULL;
return node;
}
/* create a new sub express node */
ExprNode *
expr_node_new_sub (ExprNode *val)
{
ExprNode *node = (ExprNode*) malloc (sizeof(ExprNode));
node->expr.dt = DT_SUBEXPR;
node->expr.V.bval = val;
node->next = NULL;
return node;
}
/* free the express node list */
void
expr_node_free (ExprNode *node)
{
while (node != NULL)
{
ExprNode *tmp = node->next;
if (node->expr.dt == DT_SUBEXPR)
expr_node_free (node->expr.V.bval);
free (node);
node = tmp;
}
}
/* append node to head */
ExprNode *
expr_node_append (ExprNode *head, ExprNode *node)
{
ExprNode *tmp = head;
if (tmp == NULL) return node;
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = node;
return head;
}
/* foreach node call epfunc from head to end */
void
expr_node_foreach (ExprNode *head, EPFunc epfunc)
{
ExprNode *tmp = head;
while (tmp != NULL)
{
epfunc (tmp->expr);
tmp = tmp->next;
}
}
/* compute express list */
/* declare here */
long
expr_node_compute (ExprNode *head);
/* run operator + return long int */
static long
expr_node_opadd (ExprNode *node)
{
long rs = 0;
ExprNode *tmp = node;
if (tmp == NULL) return rs; //(+) return 0
if (tmp->expr.dt == DT_SUBEXPR)
{ rs = expr_node_compute (tmp->expr.V.bval); }
else if (tmp->expr.dt == DT_INTEGER)
{ rs = tmp->expr.V.ival; }
tmp = tmp->next;
while (tmp != NULL)
{
if (tmp->expr.dt == DT_SUBEXPR)
{
rs = rs + expr_node_compute (tmp->expr.V.bval);
}
else if (tmp->expr.dt == DT_INTEGER)
{
rs = rs + tmp->expr.V.ival;
}
tmp = tmp->next;
}
//printf ("OP add, RS : %ld\n", rs);
return rs;
}
/* run operator - return long int */
static long
expr_node_opsub (ExprNode *node)
{
long rs = 0;
ExprNode *tmp = node;
if (tmp == NULL) return rs; //(-) out err info, need arg
if (tmp->expr.dt == DT_SUBEXPR)
{ rs = expr_node_compute (tmp->expr.V.bval); }
else if (tmp->expr.dt == DT_INTEGER)
{ rs = tmp->expr.V.ival; }
tmp = tmp->next;
if (tmp == NULL) return -rs; //(- 9) ==> -9
while (tmp != NULL)
{
if (tmp->expr.dt == DT_SUBEXPR)
{
rs = rs - expr_node_compute (tmp->expr.V.bval);
}
else if (tmp->expr.dt == DT_INTEGER)
{
rs = rs - tmp->expr.V.ival;
}
tmp = tmp->next;
}
//printf ("OP sub, RS : %ld\n", rs);
return rs;
}
/* run operator * return long int */
static long
expr_node_opmul (ExprNode *node)
{
long rs = 0;
ExprNode *tmp = node;
if (tmp == NULL) return 1; //(*) return 1
if (tmp->expr.dt == DT_SUBEXPR)
{ rs = expr_node_compute (tmp->expr.V.bval); }
else if (tmp->expr.dt == DT_INTEGER)
{ rs = tmp->expr.V.ival; }
tmp = tmp->next;
while (tmp != NULL)
{
if (tmp->expr.dt == DT_SUBEXPR)
{
rs = rs * expr_node_compute (tmp->expr.V.bval);
}
else if (tmp->expr.dt == DT_INTEGER)
{
rs = rs * tmp->expr.V.ival;
}
tmp = tmp->next;
}
//printf ("OP mul, RS : %ld\n", rs);
return rs;
}
/* run operator / return long int */
static long
expr_node_opdiv (ExprNode *node)
{
long rs = 1;
ExprNode *tmp = node;
if (tmp == NULL) return 1; //(/) out err info, need arg
if (tmp->expr.dt == DT_SUBEXPR)
{ rs = expr_node_compute (tmp->expr.V.bval); }
else if (tmp->expr.dt == DT_INTEGER)
{ rs = tmp->expr.V.ival; }
tmp = tmp->next;
while (tmp != NULL)
{
if (tmp->expr.dt == DT_SUBEXPR)
{
rs = rs / expr_node_compute (tmp->expr.V.bval);
}
else if (tmp->expr.dt == DT_INTEGER)
{
rs = rs / tmp->expr.V.ival;
}
tmp = tmp->next;
}
//printf ("OP div, RS : %ld\n", rs);
return rs;
}
/* compute express list */
long
expr_node_compute (ExprNode *node)
{
long rs = 0;
ExprNode *tmp = node;
switch (tmp->expr.V.oval)
{
case '+': rs = expr_node_opadd (tmp->next); break;
case '-': rs = expr_node_opsub (tmp->next); break;
case '*': rs = expr_node_opmul (tmp->next); break;
case '/': rs = expr_node_opdiv (tmp->next); break;
}
return rs;
}
/* declare out_expinfo */
void
out_expinfo (ExprNode *head);
/* declare out_express */
void
out_express (ExprNode *head);
/* define output express info level */
static int exprlv = 0;
/* output express info */
void
out_expr_info (Expr expr)
{
for (int i = 0; i < exprlv; i++) printf (" ");
switch (expr.dt)
{
case DT_OPERATOR: printf (" OP: %c\n", expr.V.oval); break;
case DT_INTEGER : printf ("INT: %ld\n", expr.V.ival); break;
case DT_SUBEXPR : printf ("SUB:\n");
exprlv++; out_expinfo (expr.V.bval); exprlv--; break;
}
}
/* output express value */
void
out_expr_value (Expr expr)
{
switch (expr.dt)
{
case DT_OPERATOR: printf (" %c", expr.V.oval); break;
case DT_INTEGER : printf (" %ld", expr.V.ival); break;
case DT_SUBEXPR : out_express (expr.V.bval); break;
}
}
/* output full express info */
void
out_expinfo (ExprNode *head)
{
expr_node_foreach (head, out_expr_info);
}
/* output full express value */
void
out_express (ExprNode *head)
{
printf (" (");
expr_node_foreach (head, out_expr_value);
printf (" )");
}
/* define number length */
#define NBSIZE 32
/* define stack height */
#define STSIZE 32
/* parse express string to express node */
ExprNode *
parse_expr_string (char *estr)
{
ExprNode *root = NULL;
ExprNode *st[STSIZE] = {0};
char nbuf[NBSIZE] = {0};
int idx = 0, ndx = 1, lv = 0;
char c;
nbuf[0] = '+'; //default +
c = estr[idx];
while (c != 0)
{
switch (c)
{
case '0'...'9': //number
{
char n = estr[idx+1];
nbuf[ndx] = c; ndx++;
if (n == ' ' || n == ')')
{
long lt = strtol (nbuf, NULL, 10);
ExprNode *tmp = expr_node_new_int (lt);
st[lv-1] = expr_node_append (st[lv-1], tmp);
memset (nbuf, 0, NBSIZE); nbuf[0] = '+'; ndx = 1;
}
}
break;
case '+': case '-': case '*': case '/': //operator
{
if (c == '+' || c == '-')
{
char n = estr[idx+1];
if (n >= '0' && n <= '9')
{
nbuf[0] = c; break;
}
}
ExprNode *tmp = expr_node_new_op (c);
st[lv-1] = expr_node_append (st[lv-1], tmp);
}
break;
case '(':
{
lv++; //todo
if (lv > STSIZE) printf ("Error: Syntax error, Stack overflow!\n");
}
break;
case ')':
{
lv--;
if (lv == 0)
{
root = st[lv];
return root; //todo
}
else if (lv > 0)
{
ExprNode *sub = expr_node_new_sub (st[lv]);
st[lv-1] = expr_node_append (st[lv-1], sub);
st[lv] = NULL;
}
else
{ printf ("Error: Syntax error! Stack overflow!\n"); } //todo
}
break;
case ' ': //space
break;
defualt:
printf ("Syntax error!\n");
}
idx++; c = estr[idx];
}
return root;
}
/* test function */
void
test_parse (void)
{
//char *str = "(+ 10 20) (+ 30 40)"; //???
//char *str = "(+ 10 20 30 40 50)";
//char *str = "(+ 10 20 (+ 30 40 50) 60 (+ 70 80) 90)";
//char *str = "(+ 1 (+ 2 (+ 3 (+ 4 5))))";
//char *str = "(+ 10 (+ 20 (+ 30 (+ 40 50))))";
char *str = "(/ (+ 100 (- 300 200) (* 4 500)) 2)";
ExprNode *head;
head = parse_expr_string (str);
printf (" express : %s\n", str);
printf ("-------------------------\n");
out_expinfo (head);
printf ("-------------------------\n");
printf ("full expr:");
out_express (head);
printf ("\n-------------------------\n");
printf ("Result : %ld\n", expr_node_compute (head));
expr_node_free (head);
}
/* interactive evalute express */
void
eval_express (void)
{
ExprNode *elist = NULL;
char buf[1024] = {0};
int idx = 0;
char c;
printf ("REPL:> ");
c = fgetc (stdin);
while (c != EOF)
{
if (c == '\n')
{
elist = parse_expr_string (buf);
printf ("-------------------------\n");
out_expinfo (elist);
printf ("-------------------------\n");
printf ("full expr:");
out_express (elist);
printf ("\n-------------------------\n");
printf ("Result : %ld\n", expr_node_compute (elist));
memset (buf, 0, 1024);
expr_node_free (elist); elist = NULL;
printf ("REPL:> ");
idx = 0; c = fgetc (stdin);
}
else
{
buf[idx] = c;
idx++; c = fgetc (stdin);
}
}
}
/**/
int
main (int argc, char *argv[])
{
eval_express ();
return 0;
}
//-----(+ 1 (+ 2 3))-----//