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