⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclexpr.c

📁 tcl源码详细资料
💻 C
📖 第 1 页 / 共 3 页
字号:
#ifndef EXCLUDE_TCL/*  * tclExpr.c -- * *	This file contains the code to evaluate expressions for *	Tcl. * *	This implementation of floating-point support was modelled *	after an initial implementation by Bill Carpenter. * * Copyright 1987-1991 Regents of the University of California * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies.  The University of California * makes no representations about the suitability of this * software for any purpose.  It is provided "as is" without * express or implied warranty. */#include "tclInt.h"/* * The stuff below is a bit of a hack so that this file can be used * in environments that include no UNIX, i.e. no errno.  Just define * errno here. */#ifndef TCL_GENERIC_ONLY#include "tclUnix.h"#endif/* * The data structure below is used to describe an expression value, * which can be either an integer (the usual case), a double-precision * floating-point value, or a string.  A given number has only one * value at a time. */#define STATIC_STRING_SPACE 150typedef struct {    long intValue;		/* Integer value, if any. */    double  doubleValue;	/* Floating-point value, if any. */    ParseValue pv;		/* Used to hold a string value, if any. */    char staticSpace[STATIC_STRING_SPACE];				/* Storage for small strings;  large ones				 * are malloc-ed. */    int type;			/* Type of value:  TYPE_INT, TYPE_DOUBLE,				 * or TYPE_STRING. */} Value;/* * Valid values for type: */#define TYPE_INT	0#define TYPE_DOUBLE	1#define TYPE_STRING	2/* * The data structure below describes the state of parsing an expression. * It's passed among the routines in this module. */typedef struct {    char *originalExpr;		/* The entire expression, as originally				 * passed to Tcl_Expr. */    char *expr;			/* Position to the next character to be				 * scanned from the expression string. */    int token;			/* Type of the last token to be parsed from				 * expr.  See below for definitions.				 * Corresponds to the characters just				 * before expr. */} ExprInfo;/* * The token types are defined below.  In addition, there is a table * associating a precedence with each operator.  The order of types * is important.  Consult the code before changing it. */#define VALUE		0#define OPEN_PAREN	1#define CLOSE_PAREN	2#define END		3#define UNKNOWN		4/* * Binary operators: */#define MULT		8#define DIVIDE		9#define MOD		10#define PLUS		11#define MINUS		12#define LEFT_SHIFT	13#define RIGHT_SHIFT	14#define LESS		15#define GREATER		16#define LEQ		17#define GEQ		18#define EQUAL		19#define NEQ		20#define BIT_AND		21#define BIT_XOR		22#define BIT_OR		23#define AND		24#define OR		25#define QUESTY		26#define COLON		27/* * Unary operators: */#define	UNARY_MINUS	28#define NOT		29#define BIT_NOT		30/* * Precedence table.  The values for non-operator token types are ignored. */int precTable[] = {    0, 0, 0, 0, 0, 0, 0, 0,    11, 11, 11,				/* MULT, DIVIDE, MOD */    10, 10,				/* PLUS, MINUS */    9, 9,				/* LEFT_SHIFT, RIGHT_SHIFT */    8, 8, 8, 8,				/* LESS, GREATER, LEQ, GEQ */    7, 7,				/* EQUAL, NEQ */    6,					/* BIT_AND */    5,					/* BIT_XOR */    4,					/* BIT_OR */    3,					/* AND */    2,					/* OR */    1, 1,				/* QUESTY, COLON */    12, 12, 12				/* UNARY_MINUS, NOT, BIT_NOT */};/* * Mapping from operator numbers to strings;  used for error messages. */char *operatorStrings[] = {    "VALUE", "(", ")", "END", "UNKNOWN", "5", "6", "7",    "*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=",    ">=", "==", "!=", "&", "^", "|", "&&", "||", "?", ":",    "-", "!", "~"};/* * Declarations for local procedures to this file: */static int		ExprGetValue _ANSI_ARGS_((Tcl_Interp *interp,			    ExprInfo *infoPtr, int prec, Value *valuePtr));static int		ExprLex _ANSI_ARGS_((Tcl_Interp *interp,			    ExprInfo *infoPtr, Value *valuePtr));static void		ExprMakeString _ANSI_ARGS_((Value *valuePtr));static int		ExprParseString _ANSI_ARGS_((Tcl_Interp *interp,			    char *string, Value *valuePtr));static int		ExprTopLevel _ANSI_ARGS_((Tcl_Interp *interp,			    char *string, Value *valuePtr));/* *-------------------------------------------------------------- * * ExprParseString -- * *	Given a string (such as one coming from command or variable *	substitution), make a Value based on the string.  The value *	will be a floating-point or integer, if possible, or else it *	will just be a copy of the string. * * Results: *	TCL_OK is returned under normal circumstances, and TCL_ERROR *	is returned if a floating-point overflow or underflow occurred *	while reading in a number.  The value at *valuePtr is modified *	to hold a number, if possible. * * Side effects: *	None. * *-------------------------------------------------------------- */static intExprParseString(interp, string, valuePtr)    Tcl_Interp *interp;		/* Where to store error message. */    char *string;		/* String to turn into value. */    Value *valuePtr;		/* Where to store value information. 				 * Caller must have initialized pv field. */{    register char c;    /*     * Try to convert the string to a number.     */    c = *string;    if (((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')) {	char *term;	valuePtr->type = TYPE_INT;	errno = 0;	valuePtr->intValue = strtol(string, &term, 0);	c = *term;	if ((c == '\0') && (errno != ERANGE)) {	    return TCL_OK;	}	if ((c == '.') || (c == 'e') || (c == 'E') || (errno == ERANGE)) {	    errno = 0;	    valuePtr->doubleValue = strtod(string, &term);	    if (errno == ERANGE) {		Tcl_ResetResult(interp);		if (valuePtr->doubleValue == 0.0) {		    Tcl_AppendResult(interp, "floating-point value \"",			    string, "\" too small to represent",			    (char *) NULL);		} else {		    Tcl_AppendResult(interp, "floating-point value \"",			    string, "\" too large to represent",			    (char *) NULL);		}		return TCL_ERROR;	    }	    if (*term == '\0') {		valuePtr->type = TYPE_DOUBLE;		return TCL_OK;	    }	}    }    /*     * Not a valid number.  Save a string value (but don't do anything     * if it's already the value).     */    valuePtr->type = TYPE_STRING;    if (string != valuePtr->pv.buffer) {	int length, shortfall;	length = strlen(string);	valuePtr->pv.next = valuePtr->pv.buffer;	shortfall = length - (valuePtr->pv.end - valuePtr->pv.buffer);	if (shortfall > 0) {	    (*valuePtr->pv.expandProc)(&valuePtr->pv, shortfall);	}	strcpy(valuePtr->pv.buffer, string);    }    return TCL_OK;}/* *---------------------------------------------------------------------- * * ExprLex -- * *	Lexical analyzer for expression parser:  parses a single value, *	operator, or other syntactic element from an expression string. * * Results: *	TCL_OK is returned unless an error occurred while doing lexical *	analysis or executing an embedded command.  In that case a *	standard Tcl error is returned, using interp->result to hold *	an error message.  In the event of a successful return, the token *	and field in infoPtr is updated to refer to the next symbol in *	the expression string, and the expr field is advanced past that *	token;  if the token is a value, then the value is stored at *	valuePtr. * * Side effects: *	None. * *---------------------------------------------------------------------- */static intExprLex(interp, infoPtr, valuePtr)    Tcl_Interp *interp;			/* Interpreter to use for error					 * reporting. */    register ExprInfo *infoPtr;		/* Describes the state of the parse. */    register Value *valuePtr;		/* Where to store value, if that is					 * what's parsed from string.  Caller					 * must have initialized pv field					 * correctly. */{    register char *p, c;    char *var, *term;    int result;    p = infoPtr->expr;    c = *p;    while (isspace(c)) {	p++;	c = *p;    }    infoPtr->expr = p+1;    switch (c) {	case '0':	case '1':	case '2':	case '3':	case '4':	case '5':	case '6':	case '7':	case '8':	case '9':	case '.':	    /*	     * Number.  First read an integer.  Then if it looks like	     * there's a floating-point number (or if it's too big a	     * number to fit in an integer), parse it as a floating-point	     * number.	     */	    infoPtr->token = VALUE;	    valuePtr->type = TYPE_INT;	    errno = 0;	    valuePtr->intValue = strtoul(p, &term, 0);	    c = *term;	    if ((c == '.') || (c == 'e') || (c == 'E') || (errno == ERANGE)) {		char *term2;		errno = 0;		valuePtr->doubleValue = strtod(p, &term2);		if (errno == ERANGE) {		    Tcl_ResetResult(interp);		    if (valuePtr->doubleValue == 0.0) {			interp->result =				"floating-point value too small to represent";		    } else {			interp->result =				"floating-point value too large to represent";		    }		    return TCL_ERROR;		}		if (term2 == infoPtr->expr) {		    interp->result = "poorly-formed floating-point value";		    return TCL_ERROR;		}		valuePtr->type = TYPE_DOUBLE;		infoPtr->expr = term2;	    } else {		infoPtr->expr = term;	    }	    return TCL_OK;	case '$':	    /*	     * Variable.  Fetch its value, then see if it makes sense	     * as an integer or floating-point number.	     */	    infoPtr->token = VALUE;	    var = Tcl_ParseVar(interp, p, &infoPtr->expr);	    if (var == NULL) {		return TCL_ERROR;	    }	    if (((Interp *) interp)->noEval) {		valuePtr->type = TYPE_INT;		valuePtr->intValue = 0;		return TCL_OK;	    }	    return ExprParseString(interp, var, valuePtr);	case '[':	    infoPtr->token = VALUE;	    result = Tcl_Eval(interp, p+1, TCL_BRACKET_TERM,		    &infoPtr->expr);	    if (result != TCL_OK) {		return result;	    }	    infoPtr->expr++;	    if (((Interp *) interp)->noEval) {		valuePtr->type = TYPE_INT;		valuePtr->intValue = 0;		Tcl_ResetResult(interp);		return TCL_OK;	    }	    result = ExprParseString(interp, interp->result, valuePtr);	    if (result != TCL_OK) {		return result;	    }	    Tcl_ResetResult(interp);	    return TCL_OK;	case '"':	    infoPtr->token = VALUE;	    result = TclParseQuotes(interp, infoPtr->expr, '"', 0,		    &infoPtr->expr, &valuePtr->pv);	    if (result != TCL_OK) {		return result;	    }	    return ExprParseString(interp, valuePtr->pv.buffer, valuePtr);	case '{':	    infoPtr->token = VALUE;	    result = TclParseBraces(interp, infoPtr->expr, &infoPtr->expr,		    &valuePtr->pv);	    if (result != TCL_OK) {		return result;	    }	    return ExprParseString(interp, valuePtr->pv.buffer, valuePtr);	case '(':	    infoPtr->token = OPEN_PAREN;	    return TCL_OK;	case ')':	    infoPtr->token = CLOSE_PAREN;	    return TCL_OK;	case '*':	    infoPtr->token = MULT;	    return TCL_OK;	case '/':	    infoPtr->token = DIVIDE;	    return TCL_OK;	case '%':	    infoPtr->token = MOD;	    return TCL_OK;	case '+':	    infoPtr->token = PLUS;	    return TCL_OK;	case '-':	    infoPtr->token = MINUS;	    return TCL_OK;	case '?':	    infoPtr->token = QUESTY;	    return TCL_OK;	case ':':	    infoPtr->token = COLON;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -