C语言之为波兰表达式增加函数调用功能
增加比较运算的不等于功能,首先解析不等于运算符
在parse_expr_string函数的switch语句中加入:case ‘!’:
case '>' : case '<' : case '=' : case '!' :
else if ( c == '!' )
{
op[ 0 ] = c;
if ( n == '=' )
{ op[ 1 ] = n; tmp = expr_node_new_op ( op) ; idx = idx + 1 ; }
else
{ printf ( "Error: Syntax error! !???" ) ; exit ( 0 ) ; }
}
char * str = "(!= 99 100)" ;
编译运行,达到预期,效果如下:
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
. . .
# define CMP_NE 5
. . .
在expr_node_opcmp函数中加入代码如下,实现运算功能
. . .
case CMP_NE: if ( lta != ltb) ex. V. bval = BOOL_T; break ;
. . .
在expr_node_compute函数中加入代码如下,达到准确调用expr_node_opcmp函数,完成运算
case '!' :
{
if ( tmp-> expr. V. oval[ 1 ] == '=' )
rb = expr_node_opcmp ( tmp-> next, CMP_NE) ;
return rb;
}
char * str = "(!= 199 199)" ;
编译运行,达到预期
表达式:char *str = “(!= 99 100)”;的运算结果如下:
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 :
gwsong@ubuntu:~/works/notes/lisp$
表达式:char *str = “(!= 199 199)”;的运算结果如下:
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 :
gwsong@ubuntu:~/works/notes/lisp$
定义Procedure数据结构
typedef struct _Procedure Procedure;
struct _Procedure {
char * name;
void * ( * fp) ( ) ;
int reqs;
} ;
typedef void * ( * _FP) ( ) ;
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文件中加入代码如下:
static void * fn_newline ( void )
{
printf ( "\n" ) ; return NULL ;
}
static void * fn_display ( Expr ex)
{
out_expr_value ( ex) ; return NULL ;
}
void
regist_subr ( Procedure * pt, char * name, _FP fp, int reqs)
{
pt-> name = strdup ( name) ;
pt-> fp = fp;
pt-> reqs = reqs;
}
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函数,测试函数表,输出表长度,输出表中的函数名,参数数量
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) ;
}
编译运行,检查一下内存情况,效果如下:
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)时,按标识符的字符串在函数表中查找函数指针! 如果标识符不在函数表中,显示出错信息,退出程序!!! 如果在则根据函数的参数数量调用函数指针,并返回运算结果!!! 代码如下:
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
{ }
}
}
else if ( node-> expr. dt == DT_OPERATOR)
{
ex = expr_node_compute ( node) ;
}
else
{ }
return ex;
}
测试函数调用
表达式:char *str = “((display 2025) (newline))”;的功能是输出2025然后换行! 在上面的test_proc函数基础上,加入解析表达式,循环计算表达式功能! 代码如下:
void
test_proc ( void )
{
int len = 0 ;
Procedure * ptable = NULL ;
char * str = "((display 2025) (newline) (display 2025) (newline) (+ 2025 2025))" ;
Expr rs = { DT_INTEGER, 0 } ;
ExprNode * head = NULL , * tmp = 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) ;
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" ) ;
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) ;
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) ;
}
编译运行,检查内存情况,基本达到预期,效果如下:
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代码如下:
# ifndef XE_HEADER
# define XE_HEADER
# define BOOL_F 0
# define BOOL_T 1
# define CMP_BT 0
# define CMP_BE 1
# define CMP_LT 2
# define CMP_LE 3
# define CMP_EQ 4
# define CMP_NE 5
# define OPR_ADD 0
# define OPR_SUB 1
# define OPR_MUL 2
# define OPR_DIV 3
# define DT_OPERATOR 0X01
# define DT_INTEGER 0X02
# define DT_SUBEXPR 0X03
# define DT_BOOLEAN 0X04
# define DT_IDENTIF 0X05
# define DT_FUNCTION 0X06
typedef struct _ExpressNode ExprNode;
typedef struct _Express Expr;
struct _Express {
char dt;
union {
void * vval;
char oval[ 8 ] ;
long ival;
ExprNode * eval;
char bval;
char * sval;
} V;
} ;
struct _ExpressNode {
Expr expr;
ExprNode * next;
} ;
typedef void ( * EPFunc) ( Expr expr) ;
ExprNode* expr_node_new_op ( char * val) ;
ExprNode* expr_node_new_int ( long val) ;
ExprNode* expr_node_new_sub ( ExprNode * val) ;
ExprNode* expr_node_new_bool ( char val) ;
ExprNode* expr_node_new_idnt ( char * val) ;
void expr_node_free ( ExprNode * node) ;
ExprNode* expr_node_append ( ExprNode * head, ExprNode * node) ;
void expr_node_foreach ( ExprNode * head, EPFunc epfunc) ;
Expr expr_node_compute ( ExprNode * node) ;
void out_expinfo ( ExprNode * head) ;
void out_express ( ExprNode * head) ;
void out_expinfo ( ExprNode * head) ;
void out_express ( ExprNode * head) ;
ExprNode* parse_expr_string ( char * estr) ;
typedef struct _Procedure Procedure;
struct _Procedure {
char * name;
void * ( * fp) ( ) ;
int reqs;
} ;
typedef void * ( * _FP) ( ) ;
void
regist_subr ( Procedure * pt, char * name, _FP fp, int reqs) ;
Expr
expr_node_evaluate ( ExprNode * node, Procedure * ptab, int plen) ;
# endif
功能实现源码文件xe.c完整代码如下:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "xe.h"
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;
}
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;
}
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;
}
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;
}
ExprNode *
expr_node_new_idnt ( char * val)
{
ExprNode * node = ( ExprNode* ) malloc ( sizeof ( ExprNode) ) ;
node-> expr. dt = DT_IDENTIF;
node-> expr. V. sval = strdup ( val) ;
node-> next = NULL ;
return node;
}
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;
}
}
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;
}
void
expr_node_foreach ( ExprNode * head, EPFunc epfunc)
{
ExprNode * tmp = head;
while ( tmp != NULL )
{
epfunc ( tmp-> expr) ;
tmp = tmp-> next;
}
}
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 )
{
switch ( opt)
{
case OPR_ADD:
rs. V. ival = 0 ; return rs;
case OPR_SUB:
rs. V. ival = 0 ; return rs;
case OPR_MUL:
rs. V. ival = 1 ; return rs;
case OPR_DIV:
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;
return rs;
}
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 { }
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 { }
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;
}
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;
}
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
{ }
}
}
else if ( node-> expr. dt == DT_OPERATOR)
{
ex = expr_node_compute ( node) ;
}
else
{ }
return ex;
}
static int exprlv = 0 ;
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 ;
}
}
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 ;
}
}
void
out_expinfo ( ExprNode * head)
{
expr_node_foreach ( head, out_expr_info) ;
}
void
out_express ( ExprNode * head)
{
printf ( " (" ) ;
expr_node_foreach ( head, out_expr_value) ;
printf ( " )" ) ;
}
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 IDTSIZE 64
# define NBSIZE 32
# define STSIZE 32
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 ] = '+' ;
c = estr[ idx] ;
while ( c != 0 )
{
switch ( c)
{
case ';' :
peat_comment_line ( estr, & idx) ;
break ;
case 'A' . . . 'Z' : case 'a' . . . 'z' :
{
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 '#' :
{
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 ;
ExprNode * tmp = expr_node_new_bool ( b) ;
st[ lv- 1 ] = expr_node_append ( st[ lv- 1 ] , tmp) ;
idx = idx + 1 ;
}
}
break ;
case '0' . . . '9' :
{
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 '/' :
{
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 == ' ' )
{ 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) ; }
else
{ printf ( "Error: Syntax error! =???" ) ; exit ( 0 ) ; }
}
else if ( c == '!' )
{
op[ 0 ] = c;
if ( n == '=' )
{ 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) ; }
else
{ }
st[ lv- 1 ] = expr_node_append ( st[ lv- 1 ] , tmp) ;
}
break ;
case '(' :
{
lv++ ;
if ( lv > STSIZE) printf ( "Error: Syntax error, Stack overflow!\n" ) ;
}
break ;
case ')' :
{
lv-- ;
if ( lv == 0 )
{
root = st[ lv] ; return root;
}
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 ) ; }
}
break ;
case ' ' :
break ;
defualt:
printf ( "Error: Syntax error!\n" ) ; exit ( 0 ) ;
}
if ( idx == elen) break ;
idx++ ; c = estr[ idx] ;
}
return root;
}
void
test_parse ( void )
{
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) ;
}
static void * fn_newline ( void )
{
printf ( "\n" ) ; return NULL ;
}
static void * fn_display ( Expr ex)
{
out_expr_value ( ex) ; return NULL ;
}
void
regist_subr ( Procedure * pt, char * name, _FP fp, int reqs)
{
pt-> name = strdup ( name) ;
pt-> fp = fp;
pt-> reqs = reqs;
}
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 ;
}
void
test_proc ( void )
{
int len = 0 ;
Procedure * ptable = NULL ;
char * str = "((display 2025) (newline) (display 2025) (newline) (+ 2025 2025))" ;
Expr rs = { DT_INTEGER, 0 } ;
ExprNode * head = NULL , * tmp = 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) ;
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" ) ;
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) ;
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) ;
}
# define MG_DEBUG 1
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 ( ) ;
return 0 ;
}
感觉分成两个文件还不够,找函数还是不太方便,下一步分成三个文件,将测试部分代码再分成一个文件! 目前已经能解析整数、运算符、标识符、还不能解析字符串,下一步完成解析字符串,输出一个Hello world!试试!!!