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))-----//






![[Redis#12] 常用类型接口学习 | string | list](https://i-blog.csdnimg.cn/img_convert/38546501e44f4e7cca9826d9d7adad33.png)











