C语言之波兰表达式的交互运行

C语言之波兰表达式的交互运行

继续上一篇C语言之为波兰表达式增加定义和使用变量功能-CSDN博客,在原代码基础上进一步改进!

  • 目标一是让下面的LISP代码保存为文件,然后可以直接运行!
  • 目标二是让下面代码能交互输入输出!
lisp 复制代码
;;; filename: t01.scm
;;; only a test
(
  (define width 285)
  (define height 100)
  (display "Width  : ") (display width)  (newline)
  (display "Height : ") (display height) (newline)
  (display "Area   : ")
  (display (* width height))
  (newline)
)

修改文件名,xe.h改为xf.h,xe.c改为xf.c,xt.c改为te.c

  • 修改函数test_proc代码如下:
c 复制代码
/* test procedure function */
void
test_proc (void)
{
  //char *str = "((display (not #f))(newline))";
  //char *str = "((define x 90)(define y 100)(display (+ x y))(newline))";
  char *str = "((define width 285)(define height 100)(display \"Area : \")(display (* width height))(newline))";
  Expr rs = { T_INT, 0};
  ExprNode *head = NULL, *tmp = NULL;

  init_systable (); //init

  head = parse_expr_string (str); //parse express

  printf (" express :\n%s\n", str);
#if MG_DEBUG
  printf ("-------------------------\n");
  out_expinfo (head);
  printf ("-------------------------\n");
  printf ("full expr:\n");
  out_express (head);
  printf ("\n-------------------------\n");
#endif

  printf ("-----------------------------------\n");
  //eval express node
  tmp = head;
  while (tmp != NULL)
    {
      rs = expr_node_evaluate (tmp);
      if (rs.V.vval != NULL) //output result
	out_result_value (rs);
      tmp = tmp->next;
    }
  printf ("-----------------------------------\n");
  printf ("Bye!\n");
  expr_node_free (head); // free the node
  destroy_systable ();
}

编译te.c,运行test_proc函数,效果如下:

bash 复制代码
gwsong@ubuntu:~/works/notes/lisp$ gcc te.c -o te
gwsong@ubuntu:~/works/notes/lisp$ ./te
 express :
((define width 285)(define height 100)(display "Area : ")(display (* width height))(newline))
-------------------------
   SUB:
    KEYWD: define
     IDNT: width
      INT: 285
   SUB:
    KEYWD: define
     IDNT: height
      INT: 100
   SUB:
     IDNT: display
   STRING: "Area : "
   SUB:
     IDNT: display
      SUB:
          OP: *
        IDNT: width
        IDNT: height
   SUB:
     IDNT: newline
-------------------------
full expr:
 ( ( define width 285 ) ( define height 100 ) ( display "Area : " ) ( display ( * width height ) ) ( newline ) )
-------------------------
-----------------------------------
Area : 28500
-----------------------------------
Bye!
gwsong@ubuntu:~/works/notes/lisp$ 

按变量名取值

  • 定义函数get_expr_byvar代码如下:
c 复制代码
/* get expr by variable name */
static Expr
get_expr_byvar (char *name)
{
  Expr et = {0, 0};
  for (int i = 0; i < _gvtable_idx; i++)
    {
      if (0 == strcmp (name, _gvtable[i].name))
	{ et = _gvtable[i].value; break; }
    }
  return et;
}
  • 修改运算节点函数expr_node_evaluate代码如下:
c 复制代码
/* evaluate express node */
Expr
expr_node_evaluate (ExprNode *node)
{
  Expr ex = {0, 0};
  if (node->expr.dt == T_SUB) //sub express
    { ex = expr_node_evaluate (node->expr.V.eval); }
  else if (node->expr.dt == T_KYWD) //for keyword
    {
      if (0 == strcmp ("define", node->expr.V.sval)) //define
	{
	  ExprNode *inode = node->next;
	  if (inode->expr.dt == T_IDNT) // identifier, variable
	    {
	      Expr exp;
	      Variable *var;
	      ExprNode *enode = inode->next;
	      if (enode->expr.dt == T_SUB)
		{ exp = expr_node_evaluate (enode); }
	      else
		exp = enode->expr;
	      var = &(_gvtable[_gvtable_idx]);
	      memset (var->name, 0, 32);
	      memcpy (var->name, inode->expr.V.sval, strlen (inode->expr.V.sval));
	      var->value = exp;
	      _gvtable_idx = _gvtable_idx + 1;
	      //printf ("IDX : %d, VAL : %ld\n", _gvtable_idx, var->value.V.ival);
	    }
	  else
	    {} //todo out err msg
	}
      else
	{} //todo other keyword
    }
  else if (node->expr.dt == T_IDNT) //identifier, procedure
    {
      char *tname = node->expr.V.sval;
      Procedure *subr = NULL;
      for (int i = 0; i < _gptable_idx; i++)
	{
	  if (0 == strcmp (tname, _gptable[i].name))
	    { subr = &(_gptable[i]); break; }
	}
      if (subr == NULL)
	{ printf ("Error: [%s] Procedure not found!\n", tname); exit (0); }
      else
	{
	  if (subr->pt == PT_EXPR) //efp, Expr (*fp) ();
	    {
	      if (subr->reqs == 0)
		{}
	      else if (subr->reqs == 1)
		{
		  Expr exp = node->next->expr;
		  if (exp.dt == T_SUB)
		    {
		      Expr et = expr_node_evaluate (exp.V.eval);
		      ex = subr->efp (et);
		    }
		  else if (exp.dt == T_IDNT)
		    {
		      Expr et = get_expr_byvar (exp.V.sval);
		      ex = subr->efp (et);
		    }
		  else
		    { ex = subr->efp (exp); }
		}
	      else
		{} //todo other reqs = 2 etc ...
	    }
	  else
	    {
	      if (subr->reqs == 0)
		{ void *rp = subr->vfp (); if (rp == NULL) ex.V.vval = NULL; }
	      else if (subr->reqs == 1)
		{
		  Expr ex = node->next->expr;
		  if (ex.dt == T_SUB)
		    {
		      Expr et = expr_node_evaluate (ex.V.eval);
		      void *rp = subr->vfp (et);
		      if (rp == NULL) ex.V.vval = NULL;
		    }
		  else if (ex.dt == T_IDNT)
		    {
		      Expr et = get_expr_byvar (ex.V.sval);
		      void *rp = subr->vfp (et);
		      if (rp == NULL) ex.V.vval = NULL;
		    }
		  else
		    {
		      void *rp = subr->vfp (ex);
		      if (rp == NULL) ex.V.vval = NULL;
		    }
		}
	      else
		{} //todo other reqs = 2 etc ...
	    }
	}
    }
  else if (node->expr.dt == T_OPER) //operator
    { ex = expr_node_compute (node); }
  else
    {} //todo

  return ex;
}

测试函数test_eval代码如下:

c 复制代码
/* evaluate test function */
void
test_eval (void)
{
  Expr ex = {0, 0};
  ExprNode *elist = NULL, *tmp = NULL;
  char buf[1024] = {0};
  int idx = 0;
  char c;

  init_systable (); //init

  //printf ("REPL:> ");
  c = fgetc (stdin);
  while (c != EOF)
    {
      //if (c == '\n') printf ("REPL:> ");
      buf[idx] = c;
      idx++; c = fgetc (stdin);
    }

  //printf ("\n------------------------------\n");
  elist = parse_expr_string (buf);
  if (elist != NULL)
    {
      tmp = elist;
      while (tmp != NULL)
	{
	  ex = expr_node_evaluate (tmp);
	  if (ex.V.vval != NULL) //output result
	    out_result_value (ex);
	  tmp = tmp->next;
	}
      memset (buf, 0, 1024);
      expr_node_free (elist); elist = NULL;
    }

  destroy_systable (); //destroy
  //printf ("\n------------------------------\nBye!\n");
}

编辑Scheme语言代码文件t01.scm,尾缀为scm,代码如下:

* Scheme语言是LISP应用最多的方言之一,R7RS是Scheme语言的最新标准!!!

lisp 复制代码
;;; filename: t01.scm
;;; only a test
(
  (define width 285)
  (define height 100)
  (display "Width  : ") (display width)  (newline)
  (display "Height : ") (display height) (newline)
  (display "Area   : ")
  (display (* width height))
  (newline)
)

编译运行,达到预期,效果如下:

  • 注意:用管道的方式,将代码传给目标程序!!!
  • cat将t01.scm内传给管道,管道默认是标准输入输出,te读的是标准输入!
bash 复制代码
gwsong@ubuntu:~/works/notes/lisp$ gcc te.c -o te
gwsong@ubuntu:~/works/notes/lisp$ cat t01.scm | ./te
Width  : 285
Height : 100
Area   : 28500
gwsong@ubuntu:~/works/notes/lisp$ 

交互运行测试

  • 注意:表达式输入结束,按CTRL-D键,也就是结束符,这样输入结束,开始运算!!!
bash 复制代码
gwsong@ubuntu:~/works/notes/lisp$ ./te
((define x #f)
(define y (not x))
(display x)
(newline)
(display y) (newline)
)
#f
#t
gwsong@ubuntu:~/works/notes/lisp$ 

打开注释,显示REPL提示符,编译运行,效果如下:

bash 复制代码
gwsong@ubuntu:~/works/notes/lisp$ gcc te.c -o te
gwsong@ubuntu:~/works/notes/lisp$ ./te
REPL:> (
REPL:> (define w 245)
REPL:> (define h 100)
REPL:> (display "Width: ") (display w) (newline)
REPL:> (display "Height: ") (display h) (newline)
REPL:> (display "Area: ")
REPL:> (display (* w h)) (newline)
REPL:> )
REPL:> 
------------------------------
Width: 245
Height: 100
Area: 24500
------------------------------
Bye!
gwsong@ubuntu:~/works/notes/lisp$ 
  • 至此,已经实现了LISP表达式的数学运算、比较运算、变量定义、函数调用、代码运行等功能!
  • 如果要进一步开发,需要对功能重新界定,同时需要重构了!!!

完整代码如下:

  • xf.h
c 复制代码
/* filename: xf.h */
#ifndef XF_HEADER
#define XF_HEADER

/* define boolean value */
#define BOOL_F 0  //#f , false
#define BOOL_T 1  //#t , true

/* define compare type */
#define CMP_BT 0   //big than  '>'
#define CMP_BE 1   //big equal '>='
#define CMP_LT 2   //less than '<'
#define CMP_LE 3   //less equal '<='
#define CMP_EQ 4   //equal '='
#define CMP_NE 5   //not equal '!='

/* define compute type */
#define OPR_ADD 0  //add +
#define OPR_SUB 1  //sub -
#define OPR_MUL 2  //mul *
#define OPR_DIV 3  //div /

/* define express datatype */
#define DT_OPERATOR 0X01
#define DT_INTEGER  0X02
#define DT_SUBEXPR  0X03
#define DT_BOOLEAN  0X04
#define DT_IDENTIF  0X05
#define DT_STRING   0X06
#define DT_KEYWORD  0X07

/* define express node datatype */
typedef struct _ExpressNode ExprNode;

/* define string datatype */
typedef struct _String String;

/* define express struct */
typedef struct _Express Expr;

struct _Express {
  //char name[7]; //todo save variable name
  char dt; //express datatype
  union {
        void *vval; //pointer for return result
        char  oval[8]; //operator
        long  ival; //integer
    ExprNode *eval; //subexpr
        char  bval; //boolean
        char *sval; //identifiers
      String *sobj; //string
  } V;
};

/* define express node struct */
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);

/* create a new integer express node */
ExprNode* expr_node_new_int (long val);

/* create a new sub express node */
ExprNode* expr_node_new_sub (ExprNode *val);

/* create a new boolean express node */
ExprNode* expr_node_new_bool (char val);

/* create a new identifier express node */
ExprNode* expr_node_new_idnt (char *val);

/* create a new string express node */
ExprNode * expr_node_new_string (String *obj);

/* free the express node list */
void expr_node_free (ExprNode *node);

/* append node to head */
ExprNode* expr_node_append (ExprNode *head, ExprNode *node);

/* foreach node call epfunc from head to end */
void expr_node_foreach (ExprNode *head, EPFunc epfunc);

/* compute express list */
Expr expr_node_compute (ExprNode *node);

/* output express info */
void out_expinfo (ExprNode *head);

/* output express value */
void out_express (ExprNode *head);

/* output full express info */
void out_expinfo (ExprNode *head);

/* output full express value */
void out_express (ExprNode *head);

/* parse express string to express node */
ExprNode* parse_expr_string (char *estr);

/* define procedure type */
#define PT_VOID 0X41
#define PT_EXPR 0X42

/* define Procedure data struct */
typedef struct _Procedure Procedure;
struct _Procedure {
  char *name;     //procedure name
  void* (*vfp) (); //function pointer return void*
  Expr  (*efp) (); //function pointer return expr
  int  reqs;      //request args
  char pt;        //procedure type, return type
};

/* define function pointer to uese */
typedef void* (*_VFP) ();  //return void*
typedef Expr  (*_EFP) ();  //return Expr

/* add a void* function pointer to table */
void
regist_vsubr (Procedure *pt, char *name, _VFP fp, int reqs);

/* add a Expr  function pointer to table */
void
regist_esubr (Procedure *pt, char *name, _EFP fp, int reqs);

/* define string data struct */
struct _String {
  int length;
  char *elts;
};

/* create a new string */
String * string_new (char *str);

/* free the string obj */
void string_free (String *obj);

/* get the string length */
int string_length (String *obj);

/* output result express value */
void out_result_value (Expr expr);

/* define variable data struct */
typedef struct _Variable Variable;
struct _Variable {
  char varname[32];
  Expr expr;
};

/* evaluate express node with procedure table */
Expr
expr_node_evaluate (ExprNode *node);

/* init global procedure table and global variable table */
void init_systable (void);

/* destroy global procedure table and global variable table */
void destroy_systable (void);

//todo

#endif/*XF_HEADER*/
  • xf.c
c 复制代码
/* filename: xf.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "xf.h"

/* define global procedure table size */
#define GPTLSIZE 128

/* define global procedure table */
static Procedure *_gptable = NULL;

//global procedure table
static unsigned int _gptable_idx = 0;

/* define global variable table size */
#define GVTLSIZE 128

/* define global variable table */
static Variable *_gvtable = NULL;

//global variable table
static unsigned int _gvtable_idx = 0;

/*----------------------------------------*/

/* create a new operator express node */
ExprNode *
expr_node_new_op (char *val)
{
  ExprNode *node = (ExprNode*) malloc (sizeof(ExprNode));
  node->expr.dt = DT_OPERATOR;
  memset (node->expr.V.oval, 0, 8);
  for (int i = 0; i < 8; i++)
    node->expr.V.oval[i] = val[i];
  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.eval = val;
  node->next = NULL;
  return node;
}

/* create a new boolean express node */
ExprNode *
expr_node_new_bool (char val)
{
  ExprNode *node = (ExprNode*) malloc (sizeof(ExprNode));
  node->expr.dt = DT_BOOLEAN;
  node->expr.V.bval = val;
  node->next = NULL;
  return node;
}

/* create a new identifier express node */
ExprNode *
expr_node_new_idnt (char *val)
{
  ExprNode *node = (ExprNode*) malloc (sizeof(ExprNode));
  node->expr.dt = DT_IDENTIF;
  node->expr.V.sval = strdup(val); //todo
  node->next = NULL;
  return node;
}

/* create a new keyword express node */
ExprNode *
expr_node_new_kywd (char *val)
{
  ExprNode *node = (ExprNode*) malloc (sizeof(ExprNode));
  node->expr.dt = DT_KEYWORD;
  node->expr.V.sval = strdup(val); //todo
  node->next = NULL;
  return node;
}

/* create a new string express node */
ExprNode *
expr_node_new_string (String *obj)
{
  ExprNode *node = (ExprNode*) malloc (sizeof(ExprNode));
  node->expr.dt = DT_STRING;
  node->expr.V.sobj = obj;
  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)  //sub express
	expr_node_free (node->expr.V.eval);
      if (node->expr.dt == DT_IDENTIF)  //identifier
	free (node->expr.V.sval);
      if (node->expr.dt == DT_KEYWORD)  //keyword
	free (node->expr.V.sval);
      if (node->expr.dt == DT_STRING)   //string
	string_free (node->expr.V.sobj);
      free (node);
      node = tmp;
    }
}

/* append node to head */
ExprNode *
expr_node_append (ExprNode *head, ExprNode *node)
{
  ExprNode *tmp = head;
  if (head == 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 node by operator */
static Expr
expr_node_opcmpt (ExprNode *node, char opt)
{
  Expr rs;
  long lt = 1;
  ExprNode *tmp = node;
  rs.dt = DT_INTEGER; rs.V.ival = lt;
  if (tmp == NULL)  //(oper)
    {
      switch (opt)
	{
	case OPR_ADD: //(+) return 0
	  rs.V.ival = 0; return rs;
	case OPR_SUB: //(-) out err, need args, todo
	  rs.V.ival = 0; return rs;
	case OPR_MUL: //(*) return 1
	  rs.V.ival = 1; return rs;
	case OPR_DIV: //(/) out err, need args, todo
	  rs.V.ival = 1; return rs;
	}
    }
  if (tmp->expr.dt == DT_SUBEXPR)
    { rs = expr_node_compute (tmp->expr.V.eval); lt = rs.V.ival; }
  else if (tmp->expr.dt == DT_IDENTIF)
    {
      Expr et = {0, 0};
      //printf ("get identifier as variable name! [%s]\n", tmp->expr.V.sval);
      for (int i = 0; i < _gvtable_idx; i++)
	{
	  if (0 == strcmp (tmp->expr.V.sval, _gvtable[i].varname))
	    { et = _gvtable[i].expr; break; }
	}
      if (et.dt == 0)
	{
	  printf ("Error: didn't find variable %s !\n", tmp->expr.V.sval);
	  exit(0);
	}
      else if (et.dt == DT_INTEGER)
	{ lt = et.V.ival; }
      else
	{} //todo
    }
  else if (tmp->expr.dt == DT_INTEGER)
    { lt = tmp->expr.V.ival; }
  tmp = tmp->next;
  while (tmp != NULL)
    {
      if (tmp->expr.dt == DT_SUBEXPR)
	{
	  rs = expr_node_compute (tmp->expr.V.eval);
	  switch (opt)
	    {
	    case OPR_ADD: lt = lt + rs.V.ival; break;
	    case OPR_SUB: lt = lt - rs.V.ival; break;
	    case OPR_MUL: lt = lt * rs.V.ival; break;
	    case OPR_DIV: lt = lt / rs.V.ival; break;
	    }
	}
      else if (tmp->expr.dt == DT_IDENTIF)
	{
	  Expr et = {0, 0};
	  //printf ("get identifier as variable name! [%s]\n", tmp->expr.V.sval);
	  for (int i = 0; i < _gvtable_idx; i++)
	    {
	      if (0 == strcmp (tmp->expr.V.sval, _gvtable[i].varname))
		{ et = _gvtable[i].expr; break; }
	    }
	  if (et.dt == 0)
	    {
	      printf ("Error: didn't find variable %s !\n", tmp->expr.V.sval);
	      exit(0);
	    }
	  else if (et.dt == DT_INTEGER)
	    {
	      //lt = et.V.ival;
	      switch (opt)
		{
		case OPR_ADD: lt = lt + et.V.ival; break;
		case OPR_SUB: lt = lt - et.V.ival; break;
		case OPR_MUL: lt = lt * et.V.ival; break;
		case OPR_DIV: lt = lt / et.V.ival; break;
		}
	    }
	  else
	    {} //todo
	}
      else if (tmp->expr.dt == DT_INTEGER)
	{
	  switch (opt)
	    {
	    case OPR_ADD: lt = lt + tmp->expr.V.ival; break;
	    case OPR_SUB: lt = lt - tmp->expr.V.ival; break;
	    case OPR_MUL: lt = lt * tmp->expr.V.ival; break;
	    case OPR_DIV: lt = lt / tmp->expr.V.ival; break;
	    }
	}
      tmp = tmp->next;
    }
  rs.V.ival = lt;
  /*
  switch (opt)
    {
    case OPR_ADD: printf ("OP add, RS : %ld\n", lt); break;
    case OPR_SUB: printf ("OP sub, RS : %ld\n", lt); break;
    case OPR_MUL: printf ("OP mul, RS : %ld\n", lt); break;
    case OPR_DIV: printf ("OP div, RS : %ld\n", lt); break;
    }
  */
  return rs;
}

/* compare express node by operator */
static Expr
expr_node_opcmp (ExprNode *node, char ct)
{
  Expr ex = { .dt = DT_BOOLEAN, .V.bval = BOOL_F };
  ExprNode *ta = node, *tb = node->next;
  long lta = 0, ltb = 0;

  if (ta->expr.dt == DT_SUBEXPR)
    { Expr et = expr_node_compute (ta->expr.V.eval); lta = et.V.ival; }
  else if (ta->expr.dt == DT_INTEGER)
    lta = ta->expr.V.ival;
  else {} //todo out error msg

  if (tb->expr.dt == DT_SUBEXPR)
    { Expr et = expr_node_compute (tb->expr.V.eval); ltb = et.V.ival; }
  else if (tb->expr.dt == DT_INTEGER)
    ltb = tb->expr.V.ival;
  else {} //todo out error msg

  switch (ct)
    {
    case CMP_BT: if (lta >  ltb) ex.V.bval = BOOL_T; break;
    case CMP_BE: if (lta >= ltb) ex.V.bval = BOOL_T; break;
    case CMP_LT: if (lta <  ltb) ex.V.bval = BOOL_T; break;
    case CMP_LE: if (lta <= ltb) ex.V.bval = BOOL_T; break;
    case CMP_EQ: if (lta == ltb) ex.V.bval = BOOL_T; break;
    case CMP_NE: if (lta != ltb) ex.V.bval = BOOL_T; break;
    }
  return ex;
}

/* compute express list */
Expr
expr_node_compute (ExprNode *node)
{
  Expr rs, rb;
  ExprNode *tmp = node;
  rs.dt = DT_INTEGER; rs.V.ival = 0;
  rb.dt = DT_BOOLEAN; rs.V.bval = BOOL_F;
  switch (tmp->expr.V.oval[0])
    {
    case '+': rs = expr_node_opcmpt (tmp->next, OPR_ADD); break;
    case '-': rs = expr_node_opcmpt (tmp->next, OPR_SUB); break;
    case '*': rs = expr_node_opcmpt (tmp->next, OPR_MUL); break;
    case '/': rs = expr_node_opcmpt (tmp->next, OPR_DIV); break;
    case '>':
      {
	if (tmp->expr.V.oval[1] == '=')
	  rb = expr_node_opcmp (tmp->next, CMP_BE);
	else
	  rb = expr_node_opcmp (tmp->next, CMP_BT);
	return rb;
      }
    case '<':
      {
	if (tmp->expr.V.oval[1] == '=')
	  rb = expr_node_opcmp (tmp->next, CMP_LE);
	else
	  rb = expr_node_opcmp (tmp->next, CMP_LT);
	return rb;
      }
    case '=': rb = expr_node_opcmp (tmp->next, CMP_EQ); return rb;
    case '!':
      {
	if (tmp->expr.V.oval[1] == '=')
	  rb = expr_node_opcmp (tmp->next, CMP_NE);
	return rb;
      }
    }
  return rs;
}

/* evaluate express node with procedure table */
Expr
expr_node_evaluate (ExprNode *node)
{
  Expr ex = {0, 0};
  if (node->expr.dt == DT_SUBEXPR) //sub express
    { ex = expr_node_evaluate (node->expr.V.eval); }
  else if (node->expr.dt == DT_KEYWORD) //for keyword
    {
      if (0 == strcmp ("define", node->expr.V.sval)) //define
	{
	  ExprNode *inode = node->next;
	  if (inode->expr.dt == DT_IDENTIF) //variable
	    {
	      Expr exp;
	      Variable *var;
	      ExprNode *enode = inode->next;
	      if (enode->expr.dt == DT_SUBEXPR)
		{ exp = expr_node_evaluate (enode); }
	      else
		exp = enode->expr;
	      var = &(_gvtable[_gvtable_idx]);
	      memset (var->varname, 0, 32);
	      memcpy (var->varname, inode->expr.V.sval, strlen (inode->expr.V.sval));
	      var->expr = exp;
	      _gvtable_idx = _gvtable_idx + 1;
	      //printf ("IDX : %d, VAL : %ld\n", _gvtable_idx, var->expr.V.ival);
	    }
	  else
	    {} //todo out err msg
	}
      else
	{} //todo other keyword
    }
  else if (node->expr.dt == DT_IDENTIF)
    {
      char *tname = node->expr.V.sval;
      Procedure *subr = NULL;
      for (int i = 0; i < _gptable_idx; i++)
	{
	  if (0 == strcmp (tname, _gptable[i].name))
	    { subr = &(_gptable[i]); break; }
	}
      if (subr == NULL)
	{ printf ("Error: [%s] Procedure not found!\n", tname); exit (0); }
      else
	{
	  if (subr->pt == PT_EXPR)
	    {
	      if (subr->reqs == 0)
		{}
	      else if (subr->reqs == 1)
		{
		  Expr exp = node->next->expr;
		  if (exp.dt == DT_SUBEXPR)
		    {
		      Expr ep = expr_node_evaluate (exp.V.eval);
		      ex = subr->efp (ep);
		    }
		  else
		    { ex = subr->efp (exp); }
		}
	      else
		{} //todo
	    }
	  else
	    {
	      if (subr->reqs == 0)
		{ void *rp = subr->vfp (); if (rp == NULL) ex.V.vval = NULL; }
	      else if (subr->reqs == 1)
		{
		  Expr ex = node->next->expr;
		  if (ex.dt == DT_SUBEXPR)
		    {
		      Expr ep = expr_node_evaluate (ex.V.eval);
		      void *rp = subr->vfp (ep);
		      if (rp == NULL) ex.V.vval = NULL;
		      //printf ("......NEST!\n");
		    }
		  else
		    {
		      void *rp = subr->vfp (ex);
		      if (rp == NULL) ex.V.vval = NULL;
		    }
		}
	      else
		{} //todo
	    }
	}
    }
  else if (node->expr.dt == DT_OPERATOR) //operator
    { ex = expr_node_compute (node); }
  else
    {} //todo

  return ex;
}

/*----------------------------------------*/

/* 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: %s\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.eval); exprlv--; break;
    case DT_BOOLEAN : printf ("  BOOL: %s\n",
			      ((expr.V.bval == BOOL_F) ? "false" : "true")); break;
    case DT_IDENTIF : printf ("  IDNT: %s\n", expr.V.sval); break;
    case DT_KEYWORD : printf (" KEYWD: %s\n", expr.V.sval); break;
    case DT_STRING  : printf ("STRING: \"%s\"\n", expr.V.sobj->elts); break;
    }
}

/* output express value */
void
out_expr_value (Expr expr)
{
  switch (expr.dt)
    {
    case DT_OPERATOR: printf (" %s",  expr.V.oval); break;
    case DT_INTEGER : printf (" %ld", expr.V.ival); break;
    case DT_SUBEXPR : out_express (expr.V.eval); break; //printf ("\n");
    case DT_BOOLEAN : printf (" %s", ((expr.V.bval == BOOL_F) ? "#f" : "#t")); break;
    case DT_IDENTIF : printf (" %s", expr.V.sval); break;
    case DT_KEYWORD : printf (" %s", expr.V.sval); break;
    case DT_STRING  : printf (" \"%s\"", expr.V.sobj->elts); 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 (" )");
}

/*----------------------------------------*/

/* if is a keyword return 1 else return 0 */
static int
is_keyword (char *kstr)
{
  char *keywords[20] = {
    "else",  "=>",     "define", "unquote", "unquote-splicing",
    "quote", "lambda", "if",     "set!",    "begin",
    "cond",  "and",    "or",     "case",    "let",
    "let*",  "letrec", "do",     "delay",   "quasiquote"
  };
  for (int i = 0; i < 20; i++)
    if (0 == strcmp (kstr, keywords[i])) return 1;
  return 0;
}

/* eat comment line */
static void
peat_comment_line (char *st, int *edx)
{
  int idx = *edx;
  char c = st[idx];
  while (c != 0)
    {
      if (c == '\n') break;
      idx++; c = st[idx];
    }
  *edx = idx;
}

/* define string buffer length */
#define STRSIZE 1024

/* get a string */
static String*
pget_string (char *st, int *edx)
{
  String *sobj = NULL;
  char buf[STRSIZE] = {0};
  int idx = *edx, sdx = 0;
  char c = st[idx];
  while (c != 0)
    {
      if (c == '\"') break;
      buf[sdx] = c; sdx++;
      idx++; c = st[idx];
    }
  *edx = idx;
  sobj = string_new (buf);
  return sobj;
}

/* define identifier length */
#define IDTSIZE 64

/* 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;
  int elen = strlen (estr);
  char ibuf[IDTSIZE] = {0};
  int tdx = 0, tflag = 0;
  char c;

  nbuf[0] = '+'; //default +
  c = estr[idx];
  while (c != 0)
    {
      switch (c)
	{
	case ';': //comment line
	  peat_comment_line (estr, &idx);
	  break;

	case 'A'...'Z': case 'a'...'z': //identifier
	  {
	    char n = estr[idx+1];
	    ibuf[tdx] = c; tdx++;
	    if (n == ' ' || n == ')' || n == ';')
	      {
		ExprNode *tmp;
		if (is_keyword(ibuf))
		  tmp = expr_node_new_kywd (ibuf);
		else
		  tmp = expr_node_new_idnt (ibuf);
		st[lv-1] = expr_node_append (st[lv-1], tmp);
		memset (ibuf, 0, IDTSIZE); tdx = 0;
	      }
	  }
	  break;

	case '#': //sharp
	  {
	    char n = estr[idx+1];
	    char m = estr[idx+2];
	    if (m == ' ' || m == ')' || m == ';')
	      {
		char b = -1;
		if      (n == 'f') b = BOOL_F;
		else if (n == 't') b = BOOL_T;
		else break; //todo
		ExprNode *tmp = expr_node_new_bool (b);
		st[lv-1] = expr_node_append (st[lv-1], tmp);
		idx = idx + 1;
	      }
	    //todo
	  }
	  break;

	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; }
	      }
	    char op[8] = {0}; op[0] = c;
	    ExprNode *tmp = expr_node_new_op (op);
	    st[lv-1] = expr_node_append (st[lv-1], tmp);
	  }
	  break;

	case '>': case '<': case '=': case '!': //compare
	  {
	    ExprNode *tmp;
	    char op[8] = {0};
	    char n = estr[idx+1];
	    op[0] = c;
	    if (c == '>' || c == '<')
	      {
		if (n == '=')
		  {
		    char m = estr[idx+2];
		    if (m == ' ') //for '>=', '<='
		      { op[1] = n; tmp = expr_node_new_op (op); idx = idx + 1; }
		    else
		      { printf ("Error: Syntax error! =???"); exit(0); }
		  }
		else if (n == ' ')
		  { tmp = expr_node_new_op (op); } //for '>', '<'
		else
		  { printf ("Error: Syntax error! =???"); exit(0); }
	      }
	    else if (c == '!') //op !
	      {
		op[0] = c;
		if (n == '=')  //op !=
		  { op[1] = n; tmp = expr_node_new_op (op); idx = idx + 1; }
		else
		  { printf ("Error: Syntax error! !???"); exit(0); }
	      }
	    else if (c == '=')
	      { tmp = expr_node_new_op (op); } //for '='
	    else
	      {} //todo err msg
	    st[lv-1] = expr_node_append (st[lv-1], tmp);
	  }
	  break;

	case '\"': //string
	  {
	    idx++; String *sobj = pget_string (estr, &idx);
	    ExprNode *tmp = expr_node_new_string (sobj);
	    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"); exit(0); } //todo
	  }
	  break;

	case ' ': //space
	  break;

	defualt:
	  printf ("Error: Syntax error!\n"); exit(0);
	}

      if (idx == elen) break;
      idx++; c = estr[idx];
    }

  return root;
}

/*----------------------------------------*/

/* the newline function */
static void* fn_newline (void)
{
  printf ("\n"); return NULL;
}

/* the display function */
static void* fn_display (Expr ex)
{
  out_result_value (ex); return NULL;
}

/* the boolean not function */
static Expr fn_not (Expr ex)
{
  Expr rs = {0, 0};
  if (ex.dt == DT_BOOLEAN)
    {
      rs.dt = DT_BOOLEAN;
      if (ex.V.bval == BOOL_F) rs.V.bval = BOOL_T;
      else rs.V.bval = BOOL_F;
      return rs;
    }
  else
    {
      //todo output type wrong
      return rs;
    }
}

/* add a function pointer to table */
void
regist_vsubr (Procedure *pt, char *name, _VFP fp, int reqs)
{
  pt->name = strdup(name);
  pt->vfp = fp;
  pt->reqs = reqs;
  pt->pt = PT_VOID;
}

/* add a Expr  function pointer to table */
void
regist_esubr (Procedure *pt, char *name, _EFP fp, int reqs)
{
  pt->name = strdup(name);
  pt->efp = fp;
  pt->reqs = reqs;
  pt->pt = PT_EXPR;
}

/* init procedure table */
static void
init_proc_table (Procedure *ptab, int *plen)
{
  regist_vsubr (&(ptab[0]), "newline", fn_newline, 0);
  regist_vsubr (&(ptab[1]), "display", fn_display, 1);
  regist_esubr (&(ptab[2]), "not",     fn_not,     1);
  *plen = 3;
}

/*----------------------------------------*/

/* create a new string */
String *
string_new (char *str)
{
  String *obj = (String*) malloc (sizeof(String));
  int len = strlen (str);
  int ps = len / 128 + 1;
  obj->elts = (char*) malloc (ps * 128 * sizeof(char));
  memset (obj->elts, 0, ps * 128 * sizeof(char));
  memcpy (obj->elts, str, len);
  obj->length = len;
  return obj;
}

/* free the string obj */
void
string_free (String *obj)
{
  free (obj->elts);
  free (obj);
}

/* get the string length */
int
string_length (String *obj)
{
  return obj->length;
}

/*----------------------------------------*/

/* output result express value */
void
out_result_value (Expr expr)
{
  switch (expr.dt)
    {
    case DT_INTEGER: printf ("%ld", expr.V.ival); break;
    case DT_BOOLEAN: printf ("%s", ((expr.V.bval == BOOL_F) ? "#f" : "#t")); break;
    case DT_IDENTIF: printf ("%s", expr.V.sval); break;
    case DT_STRING : printf ("%s", expr.V.sobj->elts); break;
    }
}

/*----------------------------------------*/

/* init global procedure table and global variable table */
void
init_systable (void)
{
  _gptable = (Procedure*) malloc (GPTLSIZE * sizeof(Procedure));
  memset (_gptable, 0, GPTLSIZE * sizeof(Procedure));
  init_proc_table (_gptable, &_gptable_idx);

  _gvtable = (Variable*) malloc (GVTLSIZE * sizeof(Variable));
  memset (_gvtable, 0, GVTLSIZE * sizeof(Variable));
}

/* destroy global procedure table and global variable table */
void
destroy_systable (void)
{
  // free the procedure name
  for (int i = 0; i < _gptable_idx; i++)
    {
      if (_gptable[i].name != NULL) free (_gptable[i].name);
    }

  //free the procedure table
  free (_gptable);

  //todo
  //free the variable table
  free (_gvtable);
}

/*----------------------------------------*/
  • te.c
c 复制代码
/* filename : te.c */

#include "xg.c"

/* compile : gcc te.c -o te */
/*     run : ./te           */

/* output debug info on/off */
#define MG_DEBUG 1

/* test parse function */
void
test_parse (void)
{
  //char *str = "(!= 99 100)";
  //char *str = "(!= 199 199)";
  char *str = "(display \"Hello world!\")";
  Expr rs = { T_INT, 0};
  ExprNode *head;
  head = parse_expr_string (str);

  //if (head == NULL) return;
  printf ("           0123456789012345678901234567890123456789\n"); //rule
  printf (" express : %s\n", str);
  printf ("-------------------------\n");
  out_expinfo (head);
  printf ("-------------------------\n");
  printf ("full expr:");
  out_express (head);
  printf ("\n-------------------------\n");

  printf ("Result : ");
  rs = expr_node_compute (head);
  switch (rs.dt)
    {
    case T_INT : printf ("%ld\n", rs.V.ival); break;
    case T_BOOL: printf ("%s\n", ((rs.V.bval == BOOL_F) ? "#f" : "#t")); break;
    }

  expr_node_free (head);
}

/*----------------------------------------*/

/* test procedure function */
void
test_proc (void)
{
  //char *str = "((display (not #f))(newline))";
  char *str = "((define x 90)(define y 100)(display (+ x y))(newline))";
  Expr rs = { T_INT, 0};
  ExprNode *head = NULL, *tmp = NULL;

  init_systable (); //init

  head = parse_expr_string (str); //parse express

  printf (" express :\n%s\n", str);
#if MG_DEBUG
  printf ("-------------------------\n");
  out_expinfo (head);
  printf ("-------------------------\n");
  printf ("full expr:\n");
  out_express (head);
  printf ("\n-------------------------\n");
#endif

  printf ("-----------------------------------\n");
  //eval express node
  tmp = head;
  while (tmp != NULL)
    {
      rs = expr_node_evaluate (tmp);
      if (rs.V.vval != NULL) //output result
	out_result_value (rs);
      tmp = tmp->next;
    }
  printf ("-----------------------------------\n");

  expr_node_free (head); // free the node
  destroy_systable ();
}

/*----------------------------------------*/

/* interactive evalute express */
void
eval_express (void)
{
  char buf[1024] = {0};
  int idx = 0;
  char c;

  init_systable (); //init

  printf ("REPL:> ");
  c = fgetc (stdin);
  while (c != EOF)
    {
      if (c == '\n')
	{
	  Expr ex = {0, 0};
	  ExprNode *elist = NULL, *tmp = NULL;
	  elist = parse_expr_string (buf);
	  if (elist == NULL)
	    {
	      memset (buf, 0, 1024);
	      printf ("REPL:> ");
	      idx = 0; c = fgetc (stdin);
	      continue;
	    }
	  #if MG_DEBUG
	  printf ("-------------------------\n");
	  out_expinfo (elist);
	  printf ("-------------------------\n");
	  printf ("full expr:");
	  out_express (elist);
	  printf ("\n-------------------------\n");
	  //printf ("Result : ");
	  #endif

	  tmp = elist;
	  while (tmp != NULL)
	    {
	      ex = expr_node_evaluate (tmp);
	      if (ex.V.vval != NULL) //output result
		out_result_value (ex);
	      tmp = tmp->next;
	    }

	  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);
	}
    }

  destroy_systable (); //destroy
  printf ("Bye!\n");
}

/* evaluate test function */
void
test_eval (void)
{
  Expr ex = {0, 0};
  ExprNode *elist = NULL, *tmp = NULL;
  char buf[1024] = {0};
  int idx = 0;
  char c;

  init_systable (); //init

  printf ("REPL:> ");
  c = fgetc (stdin);
  while (c != EOF)
    {
      if (c == '\n') printf ("REPL:> ");
      buf[idx] = c;
      idx++; c = fgetc (stdin);
    }

  printf ("\n------------------------------\n");
  elist = parse_expr_string (buf);
  if (elist != NULL)
    {
      tmp = elist;
      while (tmp != NULL)
	{
	  ex = expr_node_evaluate (tmp);
	  if (ex.V.vval != NULL) //output result
	    out_result_value (ex);
	  tmp = tmp->next;
	}
      memset (buf, 0, 1024);
      expr_node_free (elist); elist = NULL;
    }

  destroy_systable (); //destroy
  printf ("\n------------------------------\nBye!\n");
}

/**/
int
main (int argc, char *argv[])
{
  //test_proc ();
  //test_parse ();
  //eval_express ();
  test_eval ();
  return 0;
}
//-----(display "Hello world!")-----//
相关推荐
Lill_bin2 分钟前
分页查询在数据库中的好处
java·开发语言·数据库·python·oracle·性能优化
在西湖雾雨中起舞9 分钟前
题目 1738: 排序
算法
在西湖雾雨中起舞13 分钟前
题目 2794: 求平均年龄
数据结构·c++·算法
专科在努力!25 分钟前
STL中的deque(双端队列),存储结构与使用
开发语言·c++·stl
呆呆在发呆.33 分钟前
数据结构复习总结(期末前更新)
数据结构·c++·算法·链表·贪心算法·柔性数组
Cchengzu36 分钟前
百度23届秋招研发岗A卷
开发语言·数据库·c++
AI人H哥会Java41 分钟前
【JAVA】Java项目实战—Java EE项目:客户关系管理(CRM)系统
java·开发语言·spring boot·mysql
极客小张1 小时前
基于STM32的智电表系统课题设计思路:python友好界面、ADC、UART串口、数据分析
c语言·python·stm32·单片机·数据分析·毕业设计·课程设计
cloud___fly1 小时前
力扣hot100——双指针
数据结构·算法·leetcode·贪心算法
快乐飒男1 小时前
C语言基础(结构体)
c语言·开发语言