📄 bwb_exp.c
字号:
/**************************************************************** bwb_exp.c Expression Parser for Bywater BASIC Interpreter Copyright (c) 1993, Ted A. Campbell Bywater Software email: tcamp@delphi.com Copyright and Permissions Information: All U.S. and international rights are claimed by the author, Ted A. Campbell. This software is released under the terms of the GNU General Public License (GPL), which is distributed with this software in the file "COPYING". The GPL specifies the terms under which users may copy and use the software in this distribution. A separate license is available for commercial distribution, for information on which you should contact the author.****************************************************************//*---------------------------------------------------------------*//* NOTE: Modifications marked "JBV" were made by Jon B. Volkoff, *//* 11/1995 (eidetics@cerf.net). *//*---------------------------------------------------------------*/#include <stdio.h>#include <ctype.h>#include <math.h>#include "bwbasic.h"#include "bwb_mes.h"/*************************************************************** FUNCTION: bwb_exp() DESCRIPTION: This is the function by which the expression parser is called.***************************************************************/#if ANSI_Cstruct exp_ese *bwb_exp( char *expression, int assignment, int *position )#elsestruct exp_ese *bwb_exp( expression, assignment, position ) char *expression; int assignment; int *position;#endif { struct exp_ese *rval; /* return value */ int entry_level, main_loop, err_condition; char *e; /* pointer to current string */ int r; /* return value from functions */ register int c; /* quick counter */#if OLD_WAY int adv_loop;#endif#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "entered bwb_exp(): expression <%s> assignment <%d> level <%d>", & ( expression[ *position ] ), assignment, CURTASK expsc ); bwb_debug( bwb_ebuf );#endif /* save the entry level of the expression stack in order to check it at the end of this function */ entry_level = CURTASK expsc; err_condition = FALSE; /* advance past whitespace or beginning of line segment */#if MULTISEG_LINES if ( expression[ *position ] == ':' ) { ++( *position ); }#endif adv_ws( expression, position );#if MULTISEG_LINES if ( expression[ *position ] == ':' ) { ++( *position ); adv_ws( expression, position ); }#endif /* increment the expression stack counter to get a new level */ inc_esc(); /* check to be sure there is a legitimate expression and set initial parameters for the main loop */ if ( is_eol( expression, position ) == TRUE ) { main_loop = FALSE; /* break out of loop */ } else { main_loop = TRUE; CURTASK exps[ CURTASK expsc ].pos_adv = 0; }#if OLDWAY adv_loop = TRUE; while( adv_loop == TRUE ) { switch( expression[ *position ] ) { case ' ': /* whitespace */ case '\t': ++(*position); break; case '\0': /* end of string */ case '\r': case '\n': main_loop = adv_loop = FALSE; /* break out of loop */ break; default: adv_loop = FALSE; main_loop = TRUE; CURTASK exps[ CURTASK expsc ].pos_adv = 0; break; } }#endif /* main parsing loop */ while ( main_loop == TRUE ) { /* set variable <e> to the start of the expression */ e = &( expression[ *position ] );#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): main loop, level <%d> element <%s> ", CURTASK expsc, e ); bwb_debug( bwb_ebuf );#endif /* detect the operation required at this level */ CURTASK exps[ CURTASK expsc ].operation = exp_findop( e );#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): exp_findop() returned <%d>", CURTASK exps[ CURTASK expsc ].operation ); bwb_debug( bwb_ebuf );#endif /* perform actions specific to the operation */ switch( CURTASK exps[ CURTASK expsc ].operation ) { case OP_ERROR: main_loop = FALSE; err_condition = TRUE; break; case OP_TERMINATE: /* terminate at THEN, ELSE, TO */#if INTENSIVE_DEBUG bwb_debug( "in bwb_exp(): Found OP_TERMINATE" );#endif case OP_STRJOIN: /* string join or tab */ case OP_STRTAB: main_loop = FALSE; err_condition = FALSE; dec_esc(); break; case OP_ADD: /* in the case of any numerical operation, */ case OP_SUBTRACT: case OP_MULTIPLY: case OP_DIVIDE: case OP_MODULUS: case OP_EXPONENT: case OP_INTDIVISION: case OP_GREATERTHAN: case OP_LESSTHAN: case OP_GTEQ: case OP_LTEQ: case OP_NOTEQUAL: case OP_NOT: case OP_AND: case OP_OR: case OP_XOR: case OP_IMPLIES: case OP_EQUIV: case OP_NEGATION: /* JBV */#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): operator detected." ); bwb_debug( bwb_ebuf );#endif CURTASK exps[ CURTASK expsc ].pos_adv = -1; /* set to strange number */ /* cycle through operator table to find match */ for ( c = 0; c < N_OPERATORS; ++c ) { if ( exp_ops[ c ].operation == CURTASK exps[ CURTASK expsc ].operation ) { CURTASK exps[ CURTASK expsc ].pos_adv = strlen( exp_ops[ c ].symbol ); } } if ( CURTASK exps[ CURTASK expsc ].pos_adv == -1 ) /* was a match found? */ { CURTASK exps[ CURTASK expsc ].pos_adv = 0; /* no -- set to 0 */ } break; /* and move on */ case OP_EQUALS:#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): equal sign detected." ); bwb_debug( bwb_ebuf );#endif if ( assignment == TRUE ) { CURTASK exps[ CURTASK expsc ].operation = OP_ASSIGN; } CURTASK exps[ CURTASK expsc ].pos_adv = 1; break; case PARENTHESIS: r = exp_paren( e ); break; case CONST_STRING: r = exp_strconst( e ); break; case CONST_NUMERICAL: r = exp_numconst( e );#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): return from exp_numconst(), r = <%d>", r ); bwb_debug( bwb_ebuf );#endif break; case FUNCTION:#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): calling exp_function(), expression <%s>", e ); bwb_debug( bwb_ebuf );#endif r = exp_function( e ); break; case OP_USERFNC:#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): calling exp_ufnc(), expression <%s>", e ); bwb_debug( bwb_ebuf );#endif r = exp_ufnc( e );#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): return from exp_ufnc(), buffer <%s>", &( expression[ *position ] ) ); bwb_debug( bwb_ebuf );#endif break; case VARIABLE: r = exp_variable( e ); break; default: err_condition = TRUE; main_loop = FALSE;#if PROG_ERRORS sprintf( bwb_ebuf, "in bwb_exp.c:bwb_exp(): unidentified operation (%d).", CURTASK exps[ CURTASK expsc ].operation ); bwb_error( bwb_ebuf );#else bwb_error( err_syntax );#endif break; } /* increment *position counter based on previous actions */ *position += CURTASK exps[ CURTASK expsc ].pos_adv; CURTASK exps[ CURTASK expsc ].pos_adv = 0; /* reset advance counter */#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): advanced position; r <%d> err_c <%d>", r, err_condition ); bwb_debug( bwb_ebuf );#endif#if INTENSIVE_DEBUG if ( CURTASK exps[ CURTASK expsc ].operation == OP_EQUALS ) { sprintf( bwb_ebuf, "in bwb_exp(): with OP_EQUALS: finished case" ); bwb_debug( bwb_ebuf ); }#endif /* check for end of string */ if ( is_eol( expression, position ) == TRUE ) { main_loop = FALSE; /* break out of loop */ }#if OLDWAY adv_loop = TRUE; while( adv_loop == TRUE ) { switch( expression[ *position ] ) { case ' ': /* whitespace */ case '\t': ++(*position); break; case '\0': /* end of string */ case '\r': case '\n': case ':': main_loop = adv_loop = FALSE; /* break out of loop */ break; default: adv_loop = FALSE; break; } }#endif /* get a new stack level before looping */ if ( main_loop == TRUE ) { r = inc_esc();#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): increment esc, r <%d>, err_c <%d>", r, err_condition ); bwb_debug( bwb_ebuf );#endif } /* check for error return */ if ( r == OP_ERROR ) {#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): found r == OP_ERROR." ); bwb_debug( bwb_ebuf );#endif main_loop = FALSE; err_condition = TRUE; } else { r = TRUE; } } /* end of main parsing loop */#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): breakout from main parsing loop, r <%d> err_c <%d>", r, err_condition ); bwb_debug( bwb_ebuf );#endif /* check error condition */ if ( err_condition == TRUE ) {#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "error detected in expression parser" ); bwb_debug( bwb_ebuf );#endif /* decrement the expression stack counter until it matches entry_level */ while( CURTASK expsc > entry_level ) { dec_esc(); }#if PROG_ERRORS bwb_error( "in bwb_exp(): Error detected in parsing expression" );#else bwb_error( err_syntax );#endif } /* no error; normal exit from function */ else { /* are any more operations needed? if we are still at entry level, then they are not */ /* try operations */ exp_operation( entry_level ); /* see what is on top of the stack */ if ( CURTASK expsc > ( entry_level + 1 )) { switch( CURTASK exps[ CURTASK expsc ].operation ) { case OP_STRJOIN: if ( CURTASK expsc != ( entry_level + 2 )) {#if PROG_ERRORS sprintf( bwb_ebuf, "in bwb_exp(): OP_STRJOIN in wrong position." ); bwb_error( bwb_ebuf );#else bwb_error( err_syntax );#endif } break; default:#if PROG_ERRORS sprintf( bwb_ebuf, "in bwb_exp(): incomplete expression." ); bwb_error( bwb_ebuf );#else bwb_error( err_syntax );#endif break; } /* decrement the expression stack counter */#if INTENSIVE_DEBUG sprintf( bwb_ebuf, "in bwb_exp(): before dec_esc type is <%c>", CURTASK exps[ CURTASK expsc ].type ); bwb_debug( bwb_ebuf );#endif dec_esc(); } /* assign rvar to the variable for the current level */ rval = &( CURTASK exps[ CURTASK expsc ] ); /* decrement the expression stack counter */ dec_esc(); /* check the current level before exit */ if ( entry_level != CURTASK expsc ) {#if PROG_ERRORS sprintf( bwb_ebuf, "in bwb_exp(): exit stack level (%d) does not match entry stack level (%d)", CURTASK expsc, entry_level ); bwb_error( bwb_ebuf );#else bwb_error( err_overflow );#endif } } /* return a pointer to the last stack level */ return rval; }/*************************************************************** FUNCTION: exp_findop() DESCRIPTION: This function reads the expression to find what operation is required at its stack level.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -