C语言之为波兰表达式增加函数调用功能
增加比较运算的不等于功能,首先解析不等于运算符
- 在parse_expr_string函数的switch语句中加入:case '!':
c
复制代码
case '>': case '<': case '=': case '!':
c
复制代码
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); }
}
c
复制代码
char *str = "(!= 99 100)";
编译运行,达到预期,效果如下:
bash
复制代码
gwsong@ubuntu:~/works/notes/lisp$ gcc xe.c -o xe
gwsong@ubuntu:~/works/notes/lisp$ ./xe
express : (!= 99 100)
-------------------------
OP: !=
INT: 99
INT: 100
-------------------------
full expr: ( != 99 100 )
-------------------------
Result : 0
gwsong@ubuntu:~/works/notes/lisp$
运算不等于表达式,输出结果
- 定义不等于比较类型:CMP_NE,not equal
c
复制代码
...
#define CMP_NE 5 //not equal '!='
...
- 在expr_node_opcmp函数中加入代码如下,实现运算功能
c
复制代码
...
case CMP_NE: if (lta != ltb) ex.V.bval = BOOL_T; break;
...
- 在expr_node_compute函数中加入代码如下,达到准确调用expr_node_opcmp函数,完成运算
c
复制代码
case '!':
{
if (tmp->expr.V.oval[1] == '=')
rb = expr_node_opcmp (tmp->next, CMP_NE);
return rb;
}
c
复制代码
//char *str = "(!= 99 100)";
char *str = "(!= 199 199)";
编译运行,达到预期
- 表达式:char *str = "(!= 99 100)";的运算结果如下:
bash
复制代码
gwsong@ubuntu:~/works/notes/lisp$ gcc xe.c -o xe
gwsong@ubuntu:~/works/notes/lisp$ ./xe
express : (!= 99 100)
-------------------------
OP: !=
INT: 99
INT: 100
-------------------------
full expr: ( != 99 100 )
-------------------------
Result : #t
gwsong@ubuntu:~/works/notes/lisp$
- 表达式:char *str = "(!= 199 199)";的运算结果如下:
bash
复制代码
gwsong@ubuntu:~/works/notes/lisp$ gcc xe.c -o xe
gwsong@ubuntu:~/works/notes/lisp$ ./xe
express : (!= 199 199)
-------------------------
OP: !=
INT: 199
INT: 199
-------------------------
full expr: ( != 199 199 )
-------------------------
Result : #f
gwsong@ubuntu:~/works/notes/lisp$
定义Procedure数据结构
c
复制代码
/* define Procedure data struct */
typedef struct _Procedure Procedure;
struct _Procedure {
char *name; //procedure name
void* (*fp) (); //function pointer
int reqs; //request args
};
/* define function pointer to uese */
typedef void* (*_FP) ();
/* add a function pointer to table */
void
regist_subr (Procedure *pt, char *name, _FP fp, int reqs);
实现函数表相关功能,让表达式调用函数
- 函数(function),回调函数(callback function),过程(procedure),子程序(subroutine),这些是同一功能的多种不同角度的称呼,要注意!!!
- 自定义两个函数:fn_newline和fn_display,用于表达式调用
- regist_subr函数用于向函数表添加自定义函数
- init_proc_table函数调用regist_subr来实现函数表的初始化
- 在xe.c文件中加入代码如下:
c
复制代码
/* the newline function */
static void* fn_newline (void)
{
printf ("\n"); return NULL;
}
/* the display function */
static void* fn_display (Expr ex)
{
out_expr_value (ex); return NULL;
}
/* add a function pointer to table */
void
regist_subr (Procedure *pt, char *name, _FP fp, int reqs)
{
pt->name = strdup(name);
pt->fp = fp;
pt->reqs = reqs;
}
/* init procedure table */
static void
init_proc_table (Procedure *ptab, int *plen)
{
regist_subr (&(ptab[0]), "newline", fn_newline, 0);
regist_subr (&(ptab[1]), "display", fn_display, 1);
*plen = 2;
}
编码测试
- 编写test_proc函数,测试函数表,输出表长度,输出表中的函数名,参数数量
c
复制代码
/* test procedure function */
void
test_proc (void)
{
int len = 0;
Procedure *ptable = NULL;
ptable = (Procedure*) malloc (32 * sizeof(Procedure));
memset (ptable, 0, 32*sizeof(Procedure));
init_proc_table (ptable, &len);
printf ("Procedure table length is %d\n", len);
for (int i = 0; i < 32; i++)
{
if (ptable[i].name != NULL)
{
printf ("Func%d : [%s], args: %d\n", i, ptable[i].name, ptable[i].reqs);
free (ptable[i].name);
}
}
free (ptable);
}
编译运行,检查一下内存情况,效果如下:
bash
复制代码
gwsong@ubuntu:~/works/notes/lisp$ gcc xe.c -o xe
gwsong@ubuntu:~/works/notes/lisp$ ./xe
Procedure table length is 2
Func0 : [newline], args: 0
Func1 : [display], args: 1
gwsong@ubuntu:~/works/notes/lisp$ valgrind --leak-check=yes ./xe
==32893== Memcheck, a memory error detector
==32893== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32893== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==32893== Command: ./xe
==32893==
Procedure table length is 2
Func0 : [newline], args: 0
Func1 : [display], args: 1
==32893==
==32893== HEAP SUMMARY:
==32893== in use at exit: 0 bytes in 0 blocks
==32893== total heap usage: 4 allocs, 4 frees, 1,808 bytes allocated
==32893==
==32893== All heap blocks were freed -- no leaks are possible
==32893==
==32893== For counts of detected and suppressed errors, rerun with: -v
==32893== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
gwsong@ubuntu:~/works/notes/lisp$
实现函数调用功能
- 定义expr_node_evaluate函数,实现调用函数功能
- expr_node_evaluate函数需要两个参数:函数表和函数表的长度
- 当节点类型为运算符(DT_OPERATOR)时,调用运算函数,返回结果!
- 当节点类型为子节点(DT_SUBEXPR)时,递归调用自身!
- 当节点类型为标识符(DT_IDENTIF)时,按标识符的字符串在函数表中查找函数指针!
- 如果标识符不在函数表中,显示出错信息,退出程序!!!
- 如果在则根据函数的参数数量调用函数指针,并返回运算结果!!!
- 代码如下:
c
复制代码
/* evaluate express node with procedure table */
Expr
expr_node_evaluate (ExprNode *node, Procedure *ptab, int plen)
{
Expr ex = {0, 0};
if (node->expr.dt == DT_SUBEXPR)
{
ex = expr_node_evaluate (node->expr.V.eval, ptab, plen);
}
else if (node->expr.dt == DT_IDENTIF)
{
char *tname = node->expr.V.sval;
Procedure *subr = NULL;
for (int i = 0; i < plen; i++)
{ if (0 == strcmp (tname, ptab[i].name)) { subr = &(ptab[i]); break; } }
if (subr == NULL)
{ printf ("Error: [%s] Procedure not found!\n", tname); exit (0); }
else
{
if (subr->reqs == 0)
{ void *rp = subr->fp (); if (rp == NULL) ex.V.vval = NULL; }
else if (subr->reqs == 1)
{
Expr ex = node->next->expr;
void *rp = subr->fp (ex);
if (rp == NULL) ex.V.vval = NULL;
}
else
{} //todo
}
}
else if (node->expr.dt == DT_OPERATOR)
{
ex = expr_node_compute (node);
}
else
{} //todo
return ex;
}
测试函数调用
- 表达式:char *str = "((display 2025) (newline))";的功能是输出2025然后换行!
- 在上面的test_proc函数基础上,加入解析表达式,循环计算表达式功能!
- 代码如下:
c
复制代码
/* test procedure function */
void
test_proc (void)
{
int len = 0;
Procedure *ptable = NULL;
//char *str = "((display 2025) (newline))";
//char *str = "((display 2025) (newline) (display 2026) (newline))";
//char *str = "(;aha\n(display 2025) ;oho\n(newline))";
//char *str = "((display 2025) (newline) (display #t) (newline))";
char *str = "((display 2025) (newline) (display 2025) (newline) (+ 2025 2025))";
Expr rs = { DT_INTEGER, 0};
ExprNode *head = NULL, *tmp = NULL;
/* create a length 32 procedure table */
ptable = (Procedure*) malloc (32 * sizeof(Procedure));
memset (ptable, 0, 32*sizeof(Procedure));
/* init the procedure table */
init_proc_table (ptable, &len);
printf ("Procedure table length is %d\n", len);
//parse express
head = parse_expr_string (str);
printf (" express : %s\n", str);
printf ("-------------------------\n");
out_expinfo (head);
printf ("-------------------------\n");
printf ("full expr:\n");
out_express (head);
printf ("\n-------------------------\n");
//eval express node
tmp = head;
while (tmp != NULL)
{
rs = expr_node_evaluate (tmp, ptable, 32);
if (rs.V.vval != NULL) //
{
out_expr_value (rs); printf ("\n");
}
tmp = tmp->next;
}
printf ("-------------------------\n");
expr_node_free (head); // free the node
for (int i = 0; i < 32; i++) // free the procedure name
{
if (ptable[i].name != NULL)
{
printf ("Func%d : [%s], args: %d\n", i, ptable[i].name, ptable[i].reqs);
free (ptable[i].name);
}
}
free (ptable); //free the procedure table
}
编译运行,检查内存情况,基本达到预期,效果如下:
bash
复制代码
gwsong@ubuntu:~/works/notes/lisp$ gcc xe.c -o xe
gwsong@ubuntu:~/works/notes/lisp$ ./xe
Procedure table length is 2
express : ((display 2025) (newline) (display 2025) (newline) (+ 2025 2025))
-------------------------
SUB:
IDNT: display
INT: 2025
SUB:
IDNT: newline
SUB:
IDNT: display
INT: 2025
SUB:
IDNT: newline
SUB:
OP: +
INT: 2025
INT: 2025
-------------------------
full expr:
( ( display 2025 )
( newline )
( display 2025 )
( newline )
( + 2025 2025 )
)
-------------------------
2025
2025
4050
-------------------------
Func0 : [newline], args: 0
Func1 : [display], args: 1
gwsong@ubuntu:~/works/notes/lisp$ valgrind --leak-check=yes ./xe
==33146== Memcheck, a memory error detector
==33146== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==33146== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==33146== Command: ./xe
==33146==
Procedure table length is 2
express : ((display 2025) (newline) (display 2025) (newline) (+ 2025 2025))
-------------------------
SUB:
IDNT: display
INT: 2025
SUB:
IDNT: newline
SUB:
IDNT: display
INT: 2025
SUB:
IDNT: newline
SUB:
OP: +
INT: 2025
INT: 2025
-------------------------
full expr:
( ( display 2025 )
( newline )
( display 2025 )
( newline )
( + 2025 2025 )
)
-------------------------
2025
2025
4050
-------------------------
Func0 : [newline], args: 0
Func1 : [display], args: 1
==33146==
==33146== HEAP SUMMARY:
==33146== in use at exit: 0 bytes in 0 blocks
==33146== total heap usage: 22 allocs, 22 frees, 2,176 bytes allocated
==33146==
==33146== All heap blocks were freed -- no leaks are possible
==33146==
==33146== For counts of detected and suppressed errors, rerun with: -v
==33146== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
gwsong@ubuntu:~/works/notes/lisp$
将源代码重构成两个文件,头文件xe.h代码如下:
c
复制代码
/* filename: xe.h */
#ifndef XE_HEADER
#define XE_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_FUNCTION 0X06 //todo
/* 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 {
void *vval; //pointer for return result
char oval[8]; //operator
long ival; //integer
ExprNode *eval; //subexpr
char bval; //boolean
char *sval; //identifiers
} 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);
/* 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 data struct */
typedef struct _Procedure Procedure;
struct _Procedure {
char *name; //procedure name
void* (*fp) (); //function pointer
int reqs; //request args
};
/* define function pointer to uese */
typedef void* (*_FP) ();
/* add a function pointer to table */
void
regist_subr (Procedure *pt, char *name, _FP fp, int reqs);
/* evaluate express node with procedure table */
Expr
expr_node_evaluate (ExprNode *node, Procedure *ptab, int plen);
//todo
#endif/*XE_HEADER*/
功能实现源码文件xe.c完整代码如下:
c
复制代码
/* filename: xe.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xe.h"
/* compile : gcc xe.c -o xe */
/* run : ./xe */
/* 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;
}
/* 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.eval);
if (node->expr.dt == DT_IDENTIF)
free (node->expr.V.sval);
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_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_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, Procedure *ptab, int plen)
{
Expr ex = {0, 0};
if (node->expr.dt == DT_SUBEXPR)
{
ex = expr_node_evaluate (node->expr.V.eval, ptab, plen);
}
else if (node->expr.dt == DT_IDENTIF)
{
char *tname = node->expr.V.sval;
Procedure *subr = NULL;
for (int i = 0; i < plen; i++)
{ if (0 == strcmp (tname, ptab[i].name)) { subr = &(ptab[i]); break; } }
if (subr == NULL)
{ printf ("Error: [%s] Procedure not found!\n", tname); exit (0); }
else
{
if (subr->reqs == 0)
{ void *rp = subr->fp (); if (rp == NULL) ex.V.vval = NULL; }
else if (subr->reqs == 1)
{
Expr ex = node->next->expr;
void *rp = subr->fp (ex);
if (rp == NULL) ex.V.vval = NULL;
}
else
{} //todo
}
}
else if (node->expr.dt == DT_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;
}
}
/* 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); printf ("\n"); break;
case DT_BOOLEAN : printf (" %s", ((expr.V.bval == BOOL_F) ? "#f" : "#t")); break;
case DT_IDENTIF : printf (" %s", expr.V.sval); 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 (" )");
}
/*----------------------------------------*/
/* 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 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 = 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 '!':
{
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 '(':
{
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;
}
/*----------------------------------------*/
/* test parse function */
void
test_parse (void)
{
//char *str = "(!= 99 100)";
char *str = "(!= 199 199)";
Expr rs = { DT_INTEGER, 0};
ExprNode *head;
head = parse_expr_string (str);
if (head == NULL) return;
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 DT_INTEGER: printf ("%ld\n", rs.V.ival); break;
case DT_BOOLEAN: printf ("%s\n", ((rs.V.bval == BOOL_F) ? "#f" : "#t")); break;
}
expr_node_free (head);
}
/*----------------------------------------*/
/* the newline function */
static void* fn_newline (void)
{
printf ("\n"); return NULL;
}
/* the display function */
static void* fn_display (Expr ex)
{
out_expr_value (ex); return NULL;
}
/* add a function pointer to table */
void
regist_subr (Procedure *pt, char *name, _FP fp, int reqs)
{
pt->name = strdup(name);
pt->fp = fp;
pt->reqs = reqs;
}
/* init procedure table */
static void
init_proc_table (Procedure *ptab, int *plen)
{
regist_subr (&(ptab[0]), "newline", fn_newline, 0);
regist_subr (&(ptab[1]), "display", fn_display, 1);
*plen = 2;
}
/*----------------------------------------*/
/* test procedure function */
void
test_proc (void)
{
int len = 0;
Procedure *ptable = NULL;
//char *str = "((display 2025) (newline))";
//char *str = "((display 2025) (newline) (display 2026) (newline))";
//char *str = "(;aha\n(display 2025) ;oho\n(newline))";
//char *str = "((display 2025) (newline) (display #t) (newline))";
char *str = "((display 2025) (newline) (display 2025) (newline) (+ 2025 2025))";
Expr rs = { DT_INTEGER, 0};
ExprNode *head = NULL, *tmp = NULL;
/* create a length 32 procedure table */
ptable = (Procedure*) malloc (32 * sizeof(Procedure));
memset (ptable, 0, 32*sizeof(Procedure));
/* init the procedure table */
init_proc_table (ptable, &len);
printf ("Procedure table length is %d\n", len);
//parse express
head = parse_expr_string (str);
printf (" express : %s\n", str);
printf ("-------------------------\n");
out_expinfo (head);
printf ("-------------------------\n");
printf ("full expr:\n");
out_express (head);
printf ("\n-------------------------\n");
//eval express node
tmp = head;
while (tmp != NULL)
{
rs = expr_node_evaluate (tmp, ptable, 32);
if (rs.V.vval != NULL) //
{
out_expr_value (rs); printf ("\n");
}
tmp = tmp->next;
}
printf ("-------------------------\n");
expr_node_free (head); // free the node
for (int i = 0; i < 32; i++) // free the procedure name
{
if (ptable[i].name != NULL)
{
printf ("Func%d : [%s], args: %d\n", i, ptable[i].name, ptable[i].reqs);
free (ptable[i].name);
}
}
free (ptable); //free the procedure table
}
/*----------------------------------------*/
/* output debug info on/off */
#define MG_DEBUG 1
/* 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')
{
Expr ex = {0, 0};
elist = parse_expr_string (buf);
#if MG_DEBUG
printf ("-------------------------\n");
out_expinfo (elist);
printf ("-------------------------\n");
printf ("full expr:");
out_express (elist);
printf ("\n-------------------------\n");
printf ("Result : ");
#endif
ex = expr_node_compute (elist);
switch (ex.dt)
{
case DT_INTEGER: printf ("%ld\n", ex.V.ival); break;
case DT_BOOLEAN: printf ("%s\n", ((ex.V.bval == BOOL_F) ? "#f" : "#t")); break;
}
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[])
{
test_proc ();
//test_parse ();
//eval_express ();
return 0;
}
//-----(not #f)-----//
- 感觉分成两个文件还不够,找函数还是不太方便,下一步分成三个文件,将测试部分代码再分成一个文件!
- 目前已经能解析整数、运算符、标识符、还不能解析字符串,下一步完成解析字符串,输出一个Hello world!试试!!!